From f9072621a99f3708320e898cea25fe17705aca01 Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 17 Sep 2018 09:48:19 -0700 Subject: [PATCH 01/11] Run callback as expression statement when no arg to assign to exists --- .../codefixes/convertToAsyncFunction.ts | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/services/codefixes/convertToAsyncFunction.ts b/src/services/codefixes/convertToAsyncFunction.ts index 8bd8341264a..bcc02a23e65 100644 --- a/src/services/codefixes/convertToAsyncFunction.ts +++ b/src/services/codefixes/convertToAsyncFunction.ts @@ -234,9 +234,7 @@ namespace ts.codefix { if (renameInfo) { const type = checker.getTypeAtLocation(node); - if (type) { - originalType.set(getNodeId(clone).toString(), type); - } + originalType.set(getNodeId(clone).toString(), type); } } @@ -391,9 +389,14 @@ namespace ts.codefix { return [createReturn(getSynthesizedDeepClone(node))]; } - function createVariableDeclarationOrAssignment(prevArgName: SynthIdentifier, rightHandSide: Expression, transformer: Transformer): NodeArray { + function createVariableDeclarationOrAssignment(prevArgName: SynthIdentifier | undefined, rightHandSide: Expression, transformer: Transformer): NodeArray { + if (!prevArgName || prevArgName.identifier.text.length === 0) { + // if there's no argName to assign to, there still might be side effects + return createNodeArray([createStatement(rightHandSide)]); + } if (prevArgName.types.length < prevArgName.numberOfAssignmentsOriginal) { + // if the variable has already been declared, we don't need "let" or "const" return createNodeArray([createStatement(createAssignment(getSynthesizedDeepClone(prevArgName.identifier), rightHandSide))]); } @@ -404,15 +407,13 @@ namespace ts.codefix { // should be kept up to date with isFixablePromiseArgument in suggestionDiagnostics.ts function getTransformationBody(func: Node, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier, parent: CallExpression, transformer: Transformer): NodeArray { - const hasPrevArgName = prevArgName && prevArgName.identifier.text.length > 0; const hasArgName = argName && argName.identifier.text.length > 0; const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(parent).toString()); switch (func.kind) { case SyntaxKind.NullKeyword: // do not produce a transformed statement for a null argument break; - case SyntaxKind.Identifier: - // identifier includes undefined + case SyntaxKind.Identifier: // identifier includes undefined if (!hasArgName) break; const synthCall = createCall(getSynthesizedDeepClone(func) as Identifier, /*typeArguments*/ undefined, [argName.identifier]); @@ -420,13 +421,18 @@ namespace ts.codefix { return createNodeArray([createReturn(synthCall)]); } - if (!hasPrevArgName) break; - - const type = transformer.originalTypeMap.get(getNodeId(func).toString()); - const callSignatures = type && transformer.checker.getSignaturesOfType(type, SignatureKind.Call); - const returnType = callSignatures && callSignatures[0].getReturnType(); - const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName!, createAwait(synthCall), transformer); - prevArgName!.types.push(returnType!); + const type = transformer.originalTypeMap.get(getNodeId(func).toString()) || transformer.checker.getTypeAtLocation(func); + const callSignatures = transformer.checker.getSignaturesOfType(type, SignatureKind.Call); + if (!callSignatures.length) { + // if identifier in handler has no call signatures, it's invalid + codeActionSucceeded = false; + break; + } + const returnType = callSignatures[0].getReturnType(); + const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName, createAwait(synthCall), transformer); + if (prevArgName) { + prevArgName.types.push(returnType); + } return varDeclOrAssignment; case SyntaxKind.FunctionDeclaration: @@ -462,11 +468,13 @@ namespace ts.codefix { return createNodeArray(innerCbBody); } - if (hasPrevArgName && !shouldReturn) { + if (!shouldReturn) { const type = transformer.checker.getTypeAtLocation(func); const returnType = getLastCallSignature(type, transformer.checker)!.getReturnType(); - const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName!, getSynthesizedDeepClone(funcBody) as Expression, transformer); - prevArgName!.types.push(returnType); + const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName, getSynthesizedDeepClone(funcBody) as Expression, transformer); + if (prevArgName) { + prevArgName.types.push(returnType); + } return varDeclOrAssignment; } else { @@ -474,7 +482,7 @@ namespace ts.codefix { } } default: - // We've found a transformation body we don't know how to handle, so the refactoring should no-op to avoid deleting code. + // If no cases apply, we've found a transformation body we don't know how to handle, so the refactoring should no-op to avoid deleting code. codeActionSucceeded = false; break; } From 0016fd72f749f25561a4d70ad36978d48b3505c2 Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 17 Sep 2018 09:48:24 -0700 Subject: [PATCH 02/11] Add test --- .../unittests/convertToAsyncFunction.ts | 9 +++++++++ ...oAsyncFunction_runEffectfulContinuation.js | 19 +++++++++++++++++++ ...oAsyncFunction_runEffectfulContinuation.ts | 19 +++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.js create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.ts diff --git a/src/testRunner/unittests/convertToAsyncFunction.ts b/src/testRunner/unittests/convertToAsyncFunction.ts index b58c698effd..7c138756502 100644 --- a/src/testRunner/unittests/convertToAsyncFunction.ts +++ b/src/testRunner/unittests/convertToAsyncFunction.ts @@ -1181,6 +1181,15 @@ function [#|f|]() { function [#|f|]() { return Promise.resolve().then(f ? (x => x) : (y => y)).then(q => q); } +`); + + _testConvertToAsyncFunction("convertToAsyncFunction_runEffectfulContinuation", ` +function [#|f|]() { + return fetch('https://typescriptlang.org').then(res).then(_ => console.log("done")); +} +function res(result) { + return Promise.resolve().then(x => console.log(result)); +} `); }); diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.js new file mode 100644 index 00000000000..bebd01f235a --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.js @@ -0,0 +1,19 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(res).then(_ => console.log("done")); +} +function res(result) { + return Promise.resolve().then(x => console.log(result)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const result = await fetch('https://typescriptlang.org'); + await res(result); + return console.log("done"); +} +function res(result) { + return Promise.resolve().then(x => console.log(result)); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.ts new file mode 100644 index 00000000000..bebd01f235a --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.ts @@ -0,0 +1,19 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(res).then(_ => console.log("done")); +} +function res(result) { + return Promise.resolve().then(x => console.log(result)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const result = await fetch('https://typescriptlang.org'); + await res(result); + return console.log("done"); +} +function res(result) { + return Promise.resolve().then(x => console.log(result)); +} From 1b9507ad06417036f2ba63b68dc0071d79ed4ae8 Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 17 Sep 2018 11:33:28 -0700 Subject: [PATCH 03/11] Wrap expressions returned from promises in awaits when appropriate --- .../codefixes/convertToAsyncFunction.ts | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/services/codefixes/convertToAsyncFunction.ts b/src/services/codefixes/convertToAsyncFunction.ts index bcc02a23e65..54f8d99f724 100644 --- a/src/services/codefixes/convertToAsyncFunction.ts +++ b/src/services/codefixes/convertToAsyncFunction.ts @@ -435,7 +435,6 @@ namespace ts.codefix { } return varDeclOrAssignment; - case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: // Arrow functions with block bodies { } will enter this control flow @@ -457,11 +456,11 @@ namespace ts.codefix { } return shouldReturn ? getSynthesizedDeepClones(createNodeArray(refactoredStmts)) : - removeReturns(createNodeArray(refactoredStmts), prevArgName!.identifier, transformer.constIdentifiers, seenReturnStatement); + removeReturns(createNodeArray(refactoredStmts), prevArgName!.identifier, transformer, seenReturnStatement); } else { - const funcBody = (func).body; - const innerRetStmts = getReturnStatementsWithPromiseHandlers(createReturn(funcBody as Expression)); + const funcBody = cast((func).body, isExpression); + const innerRetStmts = getReturnStatementsWithPromiseHandlers(createReturn(funcBody)); const innerCbBody = getInnerTransformationBody(transformer, innerRetStmts, prevArgName); if (innerCbBody.length > 0) { @@ -471,14 +470,16 @@ namespace ts.codefix { if (!shouldReturn) { const type = transformer.checker.getTypeAtLocation(func); const returnType = getLastCallSignature(type, transformer.checker)!.getReturnType(); - const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName, getSynthesizedDeepClone(funcBody) as Expression, transformer); + const rightHandSide = getSynthesizedDeepClone(funcBody); + const possiblyAwaitedRightHandSide = isPromiseReturningExpression(funcBody, transformer.checker) ? createAwait(rightHandSide) : rightHandSide; + const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName, possiblyAwaitedRightHandSide, transformer); if (prevArgName) { prevArgName.types.push(returnType); } return varDeclOrAssignment; } else { - return createNodeArray([createReturn(getSynthesizedDeepClone(funcBody) as Expression)]); + return createNodeArray([createReturn(getSynthesizedDeepClone(funcBody))]); } } default: @@ -495,13 +496,14 @@ namespace ts.codefix { } - function removeReturns(stmts: NodeArray, prevArgName: Identifier, constIdentifiers: Identifier[], seenReturnStatement: boolean): NodeArray { + function removeReturns(stmts: NodeArray, prevArgName: Identifier, transformer: Transformer, seenReturnStatement: boolean): NodeArray { const ret: Statement[] = []; for (const stmt of stmts) { if (isReturnStatement(stmt)) { if (stmt.expression) { + const possiblyAwaitedExpression = isPromiseReturningExpression(stmt.expression, transformer.checker) ? createAwait(stmt.expression) : stmt.expression; ret.push(createVariableStatement(/*modifiers*/ undefined, - (createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, stmt.expression)], getFlagOfIdentifier(prevArgName, constIdentifiers))))); + (createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, possiblyAwaitedExpression)], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers))))); } } else { @@ -512,7 +514,7 @@ namespace ts.codefix { // if block has no return statement, need to define prevArgName as undefined to prevent undeclared variables if (!seenReturnStatement) { ret.push(createVariableStatement(/*modifiers*/ undefined, - (createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, createIdentifier("undefined"))], getFlagOfIdentifier(prevArgName, constIdentifiers))))); + (createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, createIdentifier("undefined"))], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers))))); } return createNodeArray(ret); From ad43020c8b8386a81d9766d11d6a46df1ecbd87b Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 17 Sep 2018 11:33:47 -0700 Subject: [PATCH 04/11] Add tests --- .../unittests/convertToAsyncFunction.ts | 26 ++++++++++++++++++- .../convertToAsyncFunction_Scope1.ts | 6 ++--- ...cFunction_callbackReturnsFixablePromise.js | 14 ++++++++++ ...cFunction_callbackReturnsFixablePromise.ts | 14 ++++++++++ ...tToAsyncFunction_callbackReturnsPromise.js | 13 ++++++++++ ...tToAsyncFunction_callbackReturnsPromise.ts | 13 ++++++++++ ...cFunction_callbackReturnsPromiseInBlock.js | 13 ++++++++++ ...cFunction_callbackReturnsPromiseInBlock.ts | 13 ++++++++++ ...ction_callbackReturnsPromiseLastInChain.js | 12 +++++++++ ...ction_callbackReturnsPromiseLastInChain.ts | 12 +++++++++ 10 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsFixablePromise.js create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsFixablePromise.ts create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromise.js create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromise.ts create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseInBlock.js create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseInBlock.ts create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseLastInChain.js create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseLastInChain.ts diff --git a/src/testRunner/unittests/convertToAsyncFunction.ts b/src/testRunner/unittests/convertToAsyncFunction.ts index 7c138756502..3f8032275f5 100644 --- a/src/testRunner/unittests/convertToAsyncFunction.ts +++ b/src/testRunner/unittests/convertToAsyncFunction.ts @@ -817,7 +817,7 @@ function [#|f|]() { ); _testConvertToAsyncFunction("convertToAsyncFunction_Scope1", ` function [#|f|]() { - var var1:Promise, var2; + var var1: Response, var2; return fetch('https://typescriptlang.org').then( _ => Promise.resolve().then( res => { var2 = "test"; @@ -1190,6 +1190,30 @@ function [#|f|]() { function res(result) { return Promise.resolve().then(x => console.log(result)); } +`); + + _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromise", ` +function [#|f|]() { + return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)).then(x => console.log(x + 5)); +} +`); + + _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromiseInBlock", ` +function [#|f|]() { + return fetch('https://typescriptlang.org').then(s => { return Promise.resolve(s.statusText.length) }).then(x => x + 5); +} +`); + + _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsFixablePromise", ` +function [#|f|]() { + return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText).then(st => st.length)).then(x => console.log(x + 5)); +} +`); + + _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromiseLastInChain", ` +function [#|f|]() { + return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)); +} `); }); diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope1.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope1.ts index c9b9d40b3e3..2ce31ce1dbf 100644 --- a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope1.ts +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope1.ts @@ -1,7 +1,7 @@ // ==ORIGINAL== function /*[#|*/f/*|]*/() { - var var1:Promise, var2; + var var1: Response, var2; return fetch('https://typescriptlang.org').then( _ => Promise.resolve().then( res => { var2 = "test"; @@ -18,11 +18,11 @@ function /*[#|*/f/*|]*/() { // ==ASYNC FUNCTION::Convert to async function== async function f() { - var var1:Promise, var2; + var var1: Response, var2; await fetch('https://typescriptlang.org'); const res = await Promise.resolve(); var2 = "test"; - const res_1 = fetch("https://microsoft.com"); + const res_1 = await fetch("https://microsoft.com"); const response = var1 === res_1; return res(response); } diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsFixablePromise.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsFixablePromise.js new file mode 100644 index 00000000000..09989a79fb5 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsFixablePromise.js @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText).then(st => st.length)).then(x => console.log(x + 5)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const s = await fetch('https://typescriptlang.org'); + const st = await Promise.resolve(s.statusText); + const x = st.length; + return console.log(x + 5); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsFixablePromise.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsFixablePromise.ts new file mode 100644 index 00000000000..09989a79fb5 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsFixablePromise.ts @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText).then(st => st.length)).then(x => console.log(x + 5)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const s = await fetch('https://typescriptlang.org'); + const st = await Promise.resolve(s.statusText); + const x = st.length; + return console.log(x + 5); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromise.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromise.js new file mode 100644 index 00000000000..31ca7652f7c --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromise.js @@ -0,0 +1,13 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)).then(x => console.log(x + 5)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const s = await fetch('https://typescriptlang.org'); + const x = await Promise.resolve(s.statusText.length); + return console.log(x + 5); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromise.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromise.ts new file mode 100644 index 00000000000..31ca7652f7c --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromise.ts @@ -0,0 +1,13 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)).then(x => console.log(x + 5)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const s = await fetch('https://typescriptlang.org'); + const x = await Promise.resolve(s.statusText.length); + return console.log(x + 5); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseInBlock.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseInBlock.js new file mode 100644 index 00000000000..bde99bcc384 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseInBlock.js @@ -0,0 +1,13 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(s => { return Promise.resolve(s.statusText.length) }).then(x => x + 5); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const s = await fetch('https://typescriptlang.org'); + const x = await Promise.resolve(s.statusText.length); + return x + 5; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseInBlock.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseInBlock.ts new file mode 100644 index 00000000000..bde99bcc384 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseInBlock.ts @@ -0,0 +1,13 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(s => { return Promise.resolve(s.statusText.length) }).then(x => x + 5); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const s = await fetch('https://typescriptlang.org'); + const x = await Promise.resolve(s.statusText.length); + return x + 5; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseLastInChain.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseLastInChain.js new file mode 100644 index 00000000000..09f98a62649 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseLastInChain.js @@ -0,0 +1,12 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const s = await fetch('https://typescriptlang.org'); + return Promise.resolve(s.statusText.length); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseLastInChain.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseLastInChain.ts new file mode 100644 index 00000000000..09f98a62649 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_callbackReturnsPromiseLastInChain.ts @@ -0,0 +1,12 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const s = await fetch('https://typescriptlang.org'); + return Promise.resolve(s.statusText.length); +} From 830b3877651d08f1844332c2f8cd89a9dc16ccf2 Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 17 Sep 2018 14:34:31 -0700 Subject: [PATCH 05/11] No longer specially recognize underscore and update baselines --- src/services/codefixes/convertToAsyncFunction.ts | 2 +- .../convertToAsyncFunction_IgnoreArgs1.ts | 2 +- .../convertToAsyncFunction/convertToAsyncFunction_Scope1.ts | 2 +- .../convertToAsyncFunction_runEffectfulContinuation.js | 2 +- .../convertToAsyncFunction_runEffectfulContinuation.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/services/codefixes/convertToAsyncFunction.ts b/src/services/codefixes/convertToAsyncFunction.ts index 54f8d99f724..69a0ef7e221 100644 --- a/src/services/codefixes/convertToAsyncFunction.ts +++ b/src/services/codefixes/convertToAsyncFunction.ts @@ -558,7 +558,7 @@ namespace ts.codefix { name = getMapEntryIfExists(funcNode); } - if (!name || name.identifier === undefined || name.identifier.text === "_" || name.identifier.text === "undefined") { + if (!name || name.identifier === undefined || name.identifier.text === "undefined") { return { identifier: createIdentifier(""), types, numberOfAssignmentsOriginal }; } diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs1.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs1.ts index 2cb2ef5b32d..b3cef31ef8b 100644 --- a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs1.ts +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs1.ts @@ -6,6 +6,6 @@ function /*[#|*/f/*|]*/(): Promise { // ==ASYNC FUNCTION::Convert to async function== async function f(): Promise { - await fetch('https://typescriptlang.org'); + const _ = await fetch('https://typescriptlang.org'); console.log("done"); } \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope1.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope1.ts index 2ce31ce1dbf..ab7a707ddd0 100644 --- a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope1.ts +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope1.ts @@ -19,7 +19,7 @@ function /*[#|*/f/*|]*/() { async function f() { var var1: Response, var2; - await fetch('https://typescriptlang.org'); + const _ = await fetch('https://typescriptlang.org'); const res = await Promise.resolve(); var2 = "test"; const res_1 = await fetch("https://microsoft.com"); diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.js index bebd01f235a..4753c67cdae 100644 --- a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.js +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.js @@ -11,7 +11,7 @@ function res(result) { async function f() { const result = await fetch('https://typescriptlang.org'); - await res(result); + const _ = await res(result); return console.log("done"); } function res(result) { diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.ts index bebd01f235a..4753c67cdae 100644 --- a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.ts +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_runEffectfulContinuation.ts @@ -11,7 +11,7 @@ function res(result) { async function f() { const result = await fetch('https://typescriptlang.org'); - await res(result); + const _ = await res(result); return console.log("done"); } function res(result) { From 1a3ff452c1d8a9f2974297b5e87e35f6d38ae996 Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 17 Sep 2018 15:44:08 -0700 Subject: [PATCH 06/11] Respond to CR --- .../codefixes/convertToAsyncFunction.ts | 21 +++++++------------ .../unittests/convertToAsyncFunction.ts | 11 ++++++++++ .../convertToAsyncFunction_nestedPromises.js | 13 ++++++++++++ .../convertToAsyncFunction_nestedPromises.ts | 13 ++++++++++++ 4 files changed, 44 insertions(+), 14 deletions(-) create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_nestedPromises.js create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_nestedPromises.ts diff --git a/src/services/codefixes/convertToAsyncFunction.ts b/src/services/codefixes/convertToAsyncFunction.ts index 69a0ef7e221..910cceadcfb 100644 --- a/src/services/codefixes/convertToAsyncFunction.ts +++ b/src/services/codefixes/convertToAsyncFunction.ts @@ -14,17 +14,10 @@ namespace ts.codefix { getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, err) => convertToAsyncFunction(changes, err.file, err.start, context.program.getTypeChecker(), context)), }); - - /* - custom type to encapsulate information for variable declarations synthesized in the refactor - numberOfUsesOriginal - number of times the variable should be assigned in the refactor - numberOfUsesSynthesized - count of how many times the variable has been assigned so far - At the end of the refactor, numberOfUsesOriginal should === numberOfUsesSynthesized - */ interface SynthIdentifier { identifier: Identifier; types: Type[]; - numberOfAssignmentsOriginal: number; + numberOfAssignmentsOriginal: number; // number of times the variable should be assigned in the refactor } interface SymbolAndIdentifier { @@ -380,7 +373,7 @@ namespace ts.codefix { const hasPrevArgName = prevArgName && prevArgName.identifier.text.length > 0; const originalNodeParent = node.original ? node.original.parent : node.parent; if (hasPrevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) { - return createVariableDeclarationOrAssignment(prevArgName!, createAwait(node), transformer).concat(); // hack to make the types match + return createTransformedStatement(prevArgName!, createAwait(node), transformer).concat(); // hack to make the types match } else if (!hasPrevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) { return [createStatement(createAwait(node))]; @@ -389,7 +382,7 @@ namespace ts.codefix { return [createReturn(getSynthesizedDeepClone(node))]; } - function createVariableDeclarationOrAssignment(prevArgName: SynthIdentifier | undefined, rightHandSide: Expression, transformer: Transformer): NodeArray { + function createTransformedStatement(prevArgName: SynthIdentifier | undefined, rightHandSide: Expression, transformer: Transformer): NodeArray { if (!prevArgName || prevArgName.identifier.text.length === 0) { // if there's no argName to assign to, there still might be side effects return createNodeArray([createStatement(rightHandSide)]); @@ -429,7 +422,7 @@ namespace ts.codefix { break; } const returnType = callSignatures[0].getReturnType(); - const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName, createAwait(synthCall), transformer); + const varDeclOrAssignment = createTransformedStatement(prevArgName, createAwait(synthCall), transformer); if (prevArgName) { prevArgName.types.push(returnType); } @@ -471,12 +464,12 @@ namespace ts.codefix { const type = transformer.checker.getTypeAtLocation(func); const returnType = getLastCallSignature(type, transformer.checker)!.getReturnType(); const rightHandSide = getSynthesizedDeepClone(funcBody); - const possiblyAwaitedRightHandSide = isPromiseReturningExpression(funcBody, transformer.checker) ? createAwait(rightHandSide) : rightHandSide; - const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName, possiblyAwaitedRightHandSide, transformer); + const possiblyAwaitedRightHandSide = !!transformer.checker.getPromisedTypeOfPromise(returnType) ? createAwait(rightHandSide) : rightHandSide; + const transformedStatement = createTransformedStatement(prevArgName, possiblyAwaitedRightHandSide, transformer); if (prevArgName) { prevArgName.types.push(returnType); } - return varDeclOrAssignment; + return transformedStatement; } else { return createNodeArray([createReturn(getSynthesizedDeepClone(funcBody))]); diff --git a/src/testRunner/unittests/convertToAsyncFunction.ts b/src/testRunner/unittests/convertToAsyncFunction.ts index 3f8032275f5..d7e70e4d1e5 100644 --- a/src/testRunner/unittests/convertToAsyncFunction.ts +++ b/src/testRunner/unittests/convertToAsyncFunction.ts @@ -414,6 +414,11 @@ function [#|f|](): Promise { _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs2", ` function [#|f|](): Promise { return fetch('https://typescriptlang.org').then( () => console.log("done") ); +}` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs3", ` +function [#|f|](): Promise { + return fetch('https://typescriptlang.org').then( () => console.log("almost done") ).then( () => console.log("done") ); }` ); _testConvertToAsyncFunction("convertToAsyncFunction_Method", ` @@ -1216,6 +1221,12 @@ function [#|f|]() { } `); + +_testConvertToAsyncFunction("convertToAsyncFunction_nestedPromises", ` +function [#|f|]() { + return fetch('https://typescriptlang.org').then(x => Promise.resolve(3).then(y => Promise.resolve(x.statusText.length + y))); +} +`); }); function _testConvertToAsyncFunction(caption: string, text: string) { diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_nestedPromises.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_nestedPromises.js new file mode 100644 index 00000000000..3ce5c421c3d --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_nestedPromises.js @@ -0,0 +1,13 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(x => Promise.resolve(3).then(y => Promise.resolve(x.statusText.length + y))); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const x = await fetch('https://typescriptlang.org'); + const y = await Promise.resolve(3); + return Promise.resolve(x.statusText.length + y); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_nestedPromises.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_nestedPromises.ts new file mode 100644 index 00000000000..3ce5c421c3d --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_nestedPromises.ts @@ -0,0 +1,13 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(x => Promise.resolve(3).then(y => Promise.resolve(x.statusText.length + y))); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const x = await fetch('https://typescriptlang.org'); + const y = await Promise.resolve(3); + return Promise.resolve(x.statusText.length + y); +} From e90679ce6bbfa18a6416103a4b6e71729c02c7c8 Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 17 Sep 2018 15:52:59 -0700 Subject: [PATCH 07/11] Add baseline --- .../convertToAsyncFunction_IgnoreArgs3.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs3.ts diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs3.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs3.ts new file mode 100644 index 00000000000..60cc408a8f5 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs3.ts @@ -0,0 +1,12 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(): Promise { + return fetch('https://typescriptlang.org').then( () => console.log("almost done") ).then( () => console.log("done") ); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f(): Promise { + await fetch('https://typescriptlang.org'); + console.log("almost done"); + return console.log("done"); +} \ No newline at end of file From 099586937751ae4ced5b3471804d6bf760b8e11f Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 17 Sep 2018 15:53:15 -0700 Subject: [PATCH 08/11] Stop creating empty identifier name --- .../codefixes/convertToAsyncFunction.ts | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/services/codefixes/convertToAsyncFunction.ts b/src/services/codefixes/convertToAsyncFunction.ts index 910cceadcfb..b9b5fe150d5 100644 --- a/src/services/codefixes/convertToAsyncFunction.ts +++ b/src/services/codefixes/convertToAsyncFunction.ts @@ -311,7 +311,7 @@ namespace ts.codefix { const tryBlock = createBlock(transformExpression(node.expression, transformer, node, prevArgName)); const transformationBody = getTransformationBody(func, prevArgName, argName, node, transformer); - const catchArg = argName.identifier.text.length > 0 ? argName.identifier.text : "e"; + const catchArg = argName ? argName.identifier.text : "e"; const catchClause = createCatchClause(catchArg, createBlock(transformationBody)); /* @@ -353,7 +353,7 @@ namespace ts.codefix { const transformationBody2 = getTransformationBody(rej, prevArgName, argNameRej, node, transformer); - const catchArg = argNameRej.identifier.text.length > 0 ? argNameRej.identifier.text : "e"; + const catchArg = argNameRej ? argNameRej.identifier.text : "e"; const catchClause = createCatchClause(catchArg, createBlock(transformationBody2)); return [createTry(tryBlock, catchClause, /* finallyBlock */ undefined) as Statement]; @@ -370,12 +370,11 @@ namespace ts.codefix { function transformPromiseCall(node: Expression, transformer: Transformer, prevArgName?: SynthIdentifier): Statement[] { const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(node).toString()); // the identifier is empty when the handler (.then()) ignores the argument - In this situation we do not need to save the result of the promise returning call - const hasPrevArgName = prevArgName && prevArgName.identifier.text.length > 0; const originalNodeParent = node.original ? node.original.parent : node.parent; - if (hasPrevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) { - return createTransformedStatement(prevArgName!, createAwait(node), transformer).concat(); // hack to make the types match + if (prevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) { + return createTransformedStatement(prevArgName, createAwait(node), transformer).concat(); // hack to make the types match } - else if (!hasPrevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) { + else if (!prevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) { return [createStatement(createAwait(node))]; } @@ -398,18 +397,17 @@ namespace ts.codefix { } // should be kept up to date with isFixablePromiseArgument in suggestionDiagnostics.ts - function getTransformationBody(func: Node, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier, parent: CallExpression, transformer: Transformer): NodeArray { + function getTransformationBody(func: Node, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier | undefined, parent: CallExpression, transformer: Transformer): NodeArray { - const hasArgName = argName && argName.identifier.text.length > 0; const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(parent).toString()); switch (func.kind) { case SyntaxKind.NullKeyword: // do not produce a transformed statement for a null argument break; case SyntaxKind.Identifier: // identifier includes undefined - if (!hasArgName) break; + if (!argName) break; - const synthCall = createCall(getSynthesizedDeepClone(func) as Identifier, /*typeArguments*/ undefined, [argName.identifier]); + const synthCall = createCall(getSynthesizedDeepClone(func) as Identifier, /*typeArguments*/ undefined, argName ? [argName.identifier] : []); if (shouldReturn) { return createNodeArray([createReturn(synthCall)]); } @@ -534,7 +532,7 @@ namespace ts.codefix { return innerCbBody; } - function getArgName(funcNode: Node, transformer: Transformer): SynthIdentifier { + function getArgName(funcNode: Node, transformer: Transformer): SynthIdentifier | undefined { const numberOfAssignmentsOriginal = 0; const types: Type[] = []; @@ -552,7 +550,7 @@ namespace ts.codefix { } if (!name || name.identifier === undefined || name.identifier.text === "undefined") { - return { identifier: createIdentifier(""), types, numberOfAssignmentsOriginal }; + return undefined; } return name; From a73b561dd3b4e7eae48fbf8e30b4aec5022424e3 Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 17 Sep 2018 16:23:47 -0700 Subject: [PATCH 09/11] Ensure name for callback is generated even when it has no args --- src/services/codefixes/convertToAsyncFunction.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/codefixes/convertToAsyncFunction.ts b/src/services/codefixes/convertToAsyncFunction.ts index b9b5fe150d5..5625f5b4a55 100644 --- a/src/services/codefixes/convertToAsyncFunction.ts +++ b/src/services/codefixes/convertToAsyncFunction.ts @@ -172,9 +172,9 @@ namespace ts.codefix { // if the identifier refers to a function we want to add the new synthesized variable for the declaration (ex. blob in let blob = res(arg)) // Note - the choice of the last call signature is arbitrary - if (lastCallSignature && lastCallSignature.parameters.length && !synthNamesMap.has(symbolIdString)) { - const firstParameter = lastCallSignature.parameters[0]; - const ident = isParameter(firstParameter.valueDeclaration) && tryCast(firstParameter.valueDeclaration.name, isIdentifier) || createOptimisticUniqueName("result"); + if (lastCallSignature && !synthNamesMap.has(symbolIdString)) { + const firstParameter = firstOrUndefined(lastCallSignature.parameters); + const ident = firstParameter && isParameter(firstParameter.valueDeclaration) && tryCast(firstParameter.valueDeclaration.name, isIdentifier) || createOptimisticUniqueName("result"); const synthName = getNewNameIfConflict(ident, collidingSymbolMap); synthNamesMap.set(symbolIdString, synthName); allVarNames.push({ identifier: synthName.identifier, symbol }); From 76b0b2f1e8fc12757939fe14800317f317a5acba Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 17 Sep 2018 16:23:52 -0700 Subject: [PATCH 10/11] Add test --- .../unittests/convertToAsyncFunction.ts | 9 +++++++++ .../convertToAsyncFunction_IgnoreArgs4.js | 17 +++++++++++++++++ .../convertToAsyncFunction_IgnoreArgs4.ts | 17 +++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.js create mode 100644 tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.ts diff --git a/src/testRunner/unittests/convertToAsyncFunction.ts b/src/testRunner/unittests/convertToAsyncFunction.ts index d7e70e4d1e5..5eb49eaa445 100644 --- a/src/testRunner/unittests/convertToAsyncFunction.ts +++ b/src/testRunner/unittests/convertToAsyncFunction.ts @@ -421,6 +421,15 @@ function [#|f|](): Promise { return fetch('https://typescriptlang.org').then( () => console.log("almost done") ).then( () => console.log("done") ); }` ); + _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs4", ` +function [#|f|]() { + return fetch('https://typescriptlang.org').then(res); +} +function res(){ + console.log("done"); +}` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_Method", ` class Parser { [#|f|]():Promise { diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.js new file mode 100644 index 00000000000..a03eb467b2f --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.js @@ -0,0 +1,17 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(res); +} +function res(){ + console.log("done"); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const result_1 = await fetch('https://typescriptlang.org'); + return res(result_1); +} +function res(){ + console.log("done"); +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.ts new file mode 100644 index 00000000000..a03eb467b2f --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.ts @@ -0,0 +1,17 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch('https://typescriptlang.org').then(res); +} +function res(){ + console.log("done"); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const result_1 = await fetch('https://typescriptlang.org'); + return res(result_1); +} +function res(){ + console.log("done"); +} \ No newline at end of file From b2378ca40ca4aa29c9dd08d4dc1b1a53e45f7f64 Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 17 Sep 2018 16:33:32 -0700 Subject: [PATCH 11/11] Stop adding name of function being fixed and update baseline --- src/services/codefixes/convertToAsyncFunction.ts | 2 +- .../convertToAsyncFunction_IgnoreArgs4.js | 4 ++-- .../convertToAsyncFunction_IgnoreArgs4.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/services/codefixes/convertToAsyncFunction.ts b/src/services/codefixes/convertToAsyncFunction.ts index 5625f5b4a55..a972dff548a 100644 --- a/src/services/codefixes/convertToAsyncFunction.ts +++ b/src/services/codefixes/convertToAsyncFunction.ts @@ -172,7 +172,7 @@ namespace ts.codefix { // if the identifier refers to a function we want to add the new synthesized variable for the declaration (ex. blob in let blob = res(arg)) // Note - the choice of the last call signature is arbitrary - if (lastCallSignature && !synthNamesMap.has(symbolIdString)) { + if (lastCallSignature && !isFunctionLikeDeclaration(node.parent) && !synthNamesMap.has(symbolIdString)) { const firstParameter = firstOrUndefined(lastCallSignature.parameters); const ident = firstParameter && isParameter(firstParameter.valueDeclaration) && tryCast(firstParameter.valueDeclaration.name, isIdentifier) || createOptimisticUniqueName("result"); const synthName = getNewNameIfConflict(ident, collidingSymbolMap); diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.js index a03eb467b2f..a8cbdff4451 100644 --- a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.js +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.js @@ -9,8 +9,8 @@ function res(){ // ==ASYNC FUNCTION::Convert to async function== async function f() { - const result_1 = await fetch('https://typescriptlang.org'); - return res(result_1); + const result = await fetch('https://typescriptlang.org'); + return res(result); } function res(){ console.log("done"); diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.ts index a03eb467b2f..a8cbdff4451 100644 --- a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.ts +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs4.ts @@ -9,8 +9,8 @@ function res(){ // ==ASYNC FUNCTION::Convert to async function== async function f() { - const result_1 = await fetch('https://typescriptlang.org'); - return res(result_1); + const result = await fetch('https://typescriptlang.org'); + return res(result); } function res(){ console.log("done");