From 626f3991e7d2ba3db03304c7033728c948d59c3d Mon Sep 17 00:00:00 2001 From: Sharon Rolel Date: Mon, 8 Jan 2018 12:38:00 -0500 Subject: [PATCH 1/7] add fixAwaitInSyncFunction code fix --- src/compiler/diagnosticMessages.json | 4 ++ .../codefixes/fixAwaitInSyncFunction.ts | 52 +++++++++++++++++++ src/services/codefixes/fixes.ts | 1 + .../fourslash/codeFixAwaitInSyncFunction1.ts | 14 +++++ .../fourslash/codeFixAwaitInSyncFunction2.ts | 16 ++++++ .../fourslash/codeFixAwaitInSyncFunction3.ts | 12 +++++ .../fourslash/codeFixAwaitInSyncFunction4.ts | 9 ++++ .../fourslash/codeFixAwaitInSyncFunction5.ts | 17 ++++++ .../fourslash/codeFixAwaitInSyncFunction6.ts | 14 +++++ .../fourslash/codeFixAwaitInSyncFunction7.ts | 18 +++++++ .../codeFixAwaitInSyncFunction_all.ts | 20 +++++++ 11 files changed, 177 insertions(+) create mode 100644 src/services/codefixes/fixAwaitInSyncFunction.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction3.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction4.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 826efa6994b00..f19cda416c24b 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3843,6 +3843,10 @@ "category": "Message", "code": 90028 }, + "Convert to async": { + "category": "Message", + "code": 90028 + }, "Convert function to an ES2015 class": { "category": "Message", "code": 95001 diff --git a/src/services/codefixes/fixAwaitInSyncFunction.ts b/src/services/codefixes/fixAwaitInSyncFunction.ts new file mode 100644 index 0000000000000..e6c955fb2b419 --- /dev/null +++ b/src/services/codefixes/fixAwaitInSyncFunction.ts @@ -0,0 +1,52 @@ +/* @internal */ +namespace ts.codefix { + const fixId = "fixAwaitInSyncFunction"; + const errorCodes = [ + Diagnostics.await_expression_is_only_allowed_within_an_async_function.code, + Diagnostics.A_for_await_of_statement_is_only_allowed_within_an_async_function_or_async_generator.code, + ]; + registerCodeFix({ + errorCodes, + getCodeActions(context) { + const { sourceFile, span } = context; + const node = getNode(sourceFile, span.start); + if (!node) return undefined; + const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node)); + return [{ description: getLocaleSpecificMessage(Diagnostics.Convert_to_async), changes, fixId }]; + }, + fixIds: [fixId], + getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => + doChange(changes, context.sourceFile, getNode(diag.file, diag.start!))), + }); + + function getNode(sourceFile: SourceFile, pos: number): FunctionLikeDeclaration { + const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const containingFunction = getContainingFunction(token); + if (!isFunctionLikeDeclaration(containingFunction) || + isConstructorDeclaration(containingFunction) || + isGetAccessorDeclaration(containingFunction) || + isSetAccessorDeclaration(containingFunction)) return; + return containingFunction; + } + + function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, decl: FunctionLikeDeclaration) { + const asyncToken = createToken(SyntaxKind.AsyncKeyword); + const modifiers = decl.modifiers ? decl.modifiers.concat(asyncToken) : createNodeArray([asyncToken]); + let changed; + switch (decl.kind) { + case SyntaxKind.MethodDeclaration: + changed = createMethod(decl.decorators, modifiers, decl.asteriskToken, decl.name, decl.questionToken, decl.typeParameters, decl.parameters, decl.type, decl.body); + break; + case SyntaxKind.FunctionExpression: + changed = createFunctionExpression(modifiers, decl.asteriskToken, decl.name, decl.typeParameters, decl.parameters, decl.type, decl.body); + break; + case SyntaxKind.FunctionDeclaration: + changed = createFunctionDeclaration(decl.decorators, modifiers, decl.asteriskToken, decl.name, decl.typeParameters, decl.parameters, decl.type, decl.body); + break; + case SyntaxKind.ArrowFunction: + changed = createArrowFunction(modifiers, decl.typeParameters, decl.parameters, decl.type, decl.equalsGreaterThanToken, decl.body); + break; + } + changes.replaceNode(sourceFile, decl, changed); + } +} diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index 5b1ee8ec8572c..6049cc70295cd 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -11,6 +11,7 @@ /// /// /// +/// /// /// /// diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts new file mode 100644 index 0000000000000..9ea651efe8ade --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts @@ -0,0 +1,14 @@ +/// + +////function f() { +//// await Promise.resolve(); +////} + +verify.codeFix({ + description: "Convert to async", + index: 0, + newFileContent: +`async function f() {\r + await Promise.resolve();\r +}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts new file mode 100644 index 0000000000000..133de12ad9262 --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts @@ -0,0 +1,16 @@ +/// + +////const f = function() { +//// await Promise.resolve(); +//// await Promise.resolve(); +////} + +verify.codeFix({ + description: "Convert to async", + index: 0, + newFileContent: +`const f = async function() {\r + await Promise.resolve();\r + await Promise.resolve();\r +}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction3.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction3.ts new file mode 100644 index 0000000000000..54d0aba103be8 --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction3.ts @@ -0,0 +1,12 @@ +/// + +////const f = { +//// get a() { +//// return await Promise.resolve(); +//// }, +//// get a() { +//// await Promise.resolve(); +//// }, +////} + +verify.not.codeFixAvailable(); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction4.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction4.ts new file mode 100644 index 0000000000000..dd123e25d0bf3 --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction4.ts @@ -0,0 +1,9 @@ +/// + +////class Foo { +//// constructor { +//// await Promise.resolve(); +//// } +////} + +verify.not.codeFixAvailable(); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts new file mode 100644 index 0000000000000..c2eeab5f6b249 --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts @@ -0,0 +1,17 @@ +/// + +////class Foo { +//// bar() { +//// await Promise.resolve(); +//// } +////} + +verify.codeFix({ + description: "Convert to async", + index: 0, + newFileContent: +`class Foo { + async bar() {\r + await Promise.resolve();\r + }}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts new file mode 100644 index 0000000000000..4e0249ae26ad2 --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts @@ -0,0 +1,14 @@ +/// + +////const f = (promise) => { +//// await promise; +////} + +verify.codeFix({ + description: "Convert to async", + index: 0, + newFileContent: +`const f = async (promise) => {\r + await promise;\r +}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts new file mode 100644 index 0000000000000..7cd0bab5d79d7 --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts @@ -0,0 +1,18 @@ +/// + +////function f() { +//// for await (const x of g()) { +//// console.log(x); +//// } +////} + +verify.codeFix({ + description: "Convert to async", + index: 0, + newFileContent: +`function f() => {\r + for await (const x of g()) {\r + console.log(x);\r + }\r +}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts new file mode 100644 index 0000000000000..6d5369f0c85eb --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts @@ -0,0 +1,20 @@ +/// + +////function f() { +//// await Promise.resolve(); +////} +//// +////const g = () => { +//// await f(); +////} + +verify.codeFixAll({ + fixId: "fixAwaitInSyncFunction", + newFileContent: +`async function f() {\r + await Promise.resolve();\r +} +const g = async () => {\r + await f();\r +}`, +}); From 5dfb0c50f5494aa00668bd89c05e775022e12d11 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Mon, 8 Jan 2018 13:49:12 -0800 Subject: [PATCH 2/7] Just insert the keyword --- src/compiler/diagnosticMessages.json | 2 +- .../codefixes/fixAwaitInSyncFunction.ts | 37 +++++++------------ src/services/textChanges.ts | 5 +++ .../fourslash/codeFixAwaitInSyncFunction1.ts | 5 +-- .../fourslash/codeFixAwaitInSyncFunction2.ts | 7 ++-- .../fourslash/codeFixAwaitInSyncFunction5.ts | 8 ++-- .../codeFixAwaitInSyncFunction6.5.ts | 13 +++++++ .../fourslash/codeFixAwaitInSyncFunction6.ts | 5 +-- .../fourslash/codeFixAwaitInSyncFunction7.ts | 9 ++--- .../codeFixAwaitInSyncFunction_all.ts | 9 +++-- 10 files changed, 52 insertions(+), 48 deletions(-) create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction6.5.ts diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index f19cda416c24b..7a576556f71ee 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3845,7 +3845,7 @@ }, "Convert to async": { "category": "Message", - "code": 90028 + "code": 90029 }, "Convert function to an ES2015 class": { "category": "Message", diff --git a/src/services/codefixes/fixAwaitInSyncFunction.ts b/src/services/codefixes/fixAwaitInSyncFunction.ts index e6c955fb2b419..b6f981c82f6ef 100644 --- a/src/services/codefixes/fixAwaitInSyncFunction.ts +++ b/src/services/codefixes/fixAwaitInSyncFunction.ts @@ -9,44 +9,33 @@ namespace ts.codefix { errorCodes, getCodeActions(context) { const { sourceFile, span } = context; - const node = getNode(sourceFile, span.start); + const node = getNodeToInsertBefore(sourceFile, span.start); if (!node) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node)); return [{ description: getLocaleSpecificMessage(Diagnostics.Convert_to_async), changes, fixId }]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => - doChange(changes, context.sourceFile, getNode(diag.file, diag.start!))), + doChange(changes, context.sourceFile, getNodeToInsertBefore(diag.file, diag.start!))), }); - function getNode(sourceFile: SourceFile, pos: number): FunctionLikeDeclaration { + function getNodeToInsertBefore(sourceFile: SourceFile, pos: number): Node | undefined {//name const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); const containingFunction = getContainingFunction(token); - if (!isFunctionLikeDeclaration(containingFunction) || - isConstructorDeclaration(containingFunction) || - isGetAccessorDeclaration(containingFunction) || - isSetAccessorDeclaration(containingFunction)) return; - return containingFunction; - } - - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, decl: FunctionLikeDeclaration) { - const asyncToken = createToken(SyntaxKind.AsyncKeyword); - const modifiers = decl.modifiers ? decl.modifiers.concat(asyncToken) : createNodeArray([asyncToken]); - let changed; - switch (decl.kind) { + switch (containingFunction.kind) { case SyntaxKind.MethodDeclaration: - changed = createMethod(decl.decorators, modifiers, decl.asteriskToken, decl.name, decl.questionToken, decl.typeParameters, decl.parameters, decl.type, decl.body); - break; + return containingFunction.name; case SyntaxKind.FunctionExpression: - changed = createFunctionExpression(modifiers, decl.asteriskToken, decl.name, decl.typeParameters, decl.parameters, decl.type, decl.body); - break; case SyntaxKind.FunctionDeclaration: - changed = createFunctionDeclaration(decl.decorators, modifiers, decl.asteriskToken, decl.name, decl.typeParameters, decl.parameters, decl.type, decl.body); - break; + return findChildOfKind(containingFunction, SyntaxKind.FunctionKeyword, sourceFile); case SyntaxKind.ArrowFunction: - changed = createArrowFunction(modifiers, decl.typeParameters, decl.parameters, decl.type, decl.equalsGreaterThanToken, decl.body); - break; + return findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile) || first(containingFunction.parameters); + default: + return undefined; } - changes.replaceNode(sourceFile, decl, changed); + } + + function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, insertBefore: Node): void { + changes.insertModifierBefore(sourceFile, SyntaxKind.AsyncKeyword, insertBefore); } } diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index e73c639ba79bd..b0efef4464200 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -345,6 +345,11 @@ namespace ts.textChanges { return this.replaceWithSingle(sourceFile, startPosition, startPosition, newNode, this.getOptionsForInsertNodeBefore(before, blankLineBetween)); } + public insertModifierBefore(sourceFile: SourceFile, modifier: SyntaxKind, before: Node): void { + const pos = before.getStart(sourceFile); + this.replaceWithSingle(sourceFile, pos, pos, createToken(modifier), { suffix: " " }); + } + public changeIdentifierToPropertyAccess(sourceFile: SourceFile, prefix: string, node: Identifier): void { const startPosition = getAdjustedStartPosition(sourceFile, node, {}, Position.Start); this.replaceWithSingle(sourceFile, startPosition, startPosition, createPropertyAccess(createIdentifier(prefix), ""), {}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts index 9ea651efe8ade..bf5c50df83b80 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts @@ -6,9 +6,8 @@ verify.codeFix({ description: "Convert to async", - index: 0, newFileContent: -`async function f() {\r - await Promise.resolve();\r +`async function f() { + await Promise.resolve(); }`, }); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts index 133de12ad9262..1677d6796c85b 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts @@ -7,10 +7,9 @@ verify.codeFix({ description: "Convert to async", - index: 0, newFileContent: -`const f = async function() {\r - await Promise.resolve();\r - await Promise.resolve();\r +`const f = async function() { + await Promise.resolve(); + await Promise.resolve(); }`, }); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts index c2eeab5f6b249..3533fa0545b43 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts @@ -8,10 +8,10 @@ verify.codeFix({ description: "Convert to async", - index: 0, newFileContent: `class Foo { - async bar() {\r - await Promise.resolve();\r - }}`, + async bar() { + await Promise.resolve(); + } +}`, }); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction6.5.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction6.5.ts new file mode 100644 index 0000000000000..f71f99e8f5123 --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction6.5.ts @@ -0,0 +1,13 @@ +/// + +////const f = promise => { +//// await promise; +////} + +verify.codeFix({ + description: "Convert to async", + newFileContent: +`const f = async promise => { + await promise; +}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts index 4e0249ae26ad2..79fc2f1fbdcce 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts @@ -6,9 +6,8 @@ verify.codeFix({ description: "Convert to async", - index: 0, newFileContent: -`const f = async (promise) => {\r - await promise;\r +`const f = async (promise) => { + await promise; }`, }); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts index 7cd0bab5d79d7..dab5d8640a114 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts @@ -8,11 +8,10 @@ verify.codeFix({ description: "Convert to async", - index: 0, newFileContent: -`function f() => {\r - for await (const x of g()) {\r - console.log(x);\r - }\r +`async function f() { + for await (const x of g()) { + console.log(x); + } }`, }); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts index 6d5369f0c85eb..e6314a3a5f0a0 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts @@ -11,10 +11,11 @@ verify.codeFixAll({ fixId: "fixAwaitInSyncFunction", newFileContent: -`async function f() {\r - await Promise.resolve();\r +`async function f() { + await Promise.resolve(); } -const g = async () => {\r - await f();\r + +const g = async () => { + await f(); }`, }); From 15e916ed0e17948dda6ee95328e20992ba6dd858 Mon Sep 17 00:00:00 2001 From: Sharon Rolel Date: Mon, 8 Jan 2018 19:02:33 -0500 Subject: [PATCH 3/7] only one codefix --- tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts index 1677d6796c85b..f92320eaac7b5 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts @@ -2,7 +2,6 @@ ////const f = function() { //// await Promise.resolve(); -//// await Promise.resolve(); ////} verify.codeFix({ @@ -10,6 +9,5 @@ verify.codeFix({ newFileContent: `const f = async function() { await Promise.resolve(); - await Promise.resolve(); }`, }); From c945beb4db81b9c659031142d91a51f254a5260d Mon Sep 17 00:00:00 2001 From: Sharon Rolel Date: Mon, 8 Jan 2018 19:24:04 -0500 Subject: [PATCH 4/7] remove comment --- src/services/codefixes/fixAwaitInSyncFunction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/codefixes/fixAwaitInSyncFunction.ts b/src/services/codefixes/fixAwaitInSyncFunction.ts index b6f981c82f6ef..262e7b9186cea 100644 --- a/src/services/codefixes/fixAwaitInSyncFunction.ts +++ b/src/services/codefixes/fixAwaitInSyncFunction.ts @@ -19,7 +19,7 @@ namespace ts.codefix { doChange(changes, context.sourceFile, getNodeToInsertBefore(diag.file, diag.start!))), }); - function getNodeToInsertBefore(sourceFile: SourceFile, pos: number): Node | undefined {//name + function getNodeToInsertBefore(sourceFile: SourceFile, pos: number): Node | undefined { const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); const containingFunction = getContainingFunction(token); switch (containingFunction.kind) { From 0cb462ae589db202ccec70a6f71bf8dd4424656e Mon Sep 17 00:00:00 2001 From: Sharon Rolel Date: Tue, 9 Jan 2018 16:01:12 -0500 Subject: [PATCH 5/7] Change explicit return type T to Promise --- .../codefixes/fixAwaitInSyncFunction.ts | 47 +++++++++++++++---- .../fourslash/codeFixAwaitInSyncFunction10.ts | 13 +++++ .../fourslash/codeFixAwaitInSyncFunction11.ts | 14 ++++++ .../fourslash/codeFixAwaitInSyncFunction12.ts | 13 +++++ .../fourslash/codeFixAwaitInSyncFunction13.ts | 13 +++++ .../fourslash/codeFixAwaitInSyncFunction8.ts | 13 +++++ .../fourslash/codeFixAwaitInSyncFunction9.ts | 17 +++++++ 7 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts diff --git a/src/services/codefixes/fixAwaitInSyncFunction.ts b/src/services/codefixes/fixAwaitInSyncFunction.ts index 262e7b9186cea..06884b12af3d4 100644 --- a/src/services/codefixes/fixAwaitInSyncFunction.ts +++ b/src/services/codefixes/fixAwaitInSyncFunction.ts @@ -9,19 +9,42 @@ namespace ts.codefix { errorCodes, getCodeActions(context) { const { sourceFile, span } = context; - const node = getNodeToInsertBefore(sourceFile, span.start); - if (!node) return undefined; - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node)); + const token = getTokenAtPosition(sourceFile, span.start, /*includeJsDocComment*/ false); + const containingFunction = getContainingFunction(token); + const insertBefore = getNodeToInsertBefore(sourceFile, containingFunction); + const returnType = getReturnTypeNode(containingFunction); + if (!insertBefore) return undefined; + const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, insertBefore, returnType)); return [{ description: getLocaleSpecificMessage(Diagnostics.Convert_to_async), changes, fixId }]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => - doChange(changes, context.sourceFile, getNodeToInsertBefore(diag.file, diag.start!))), + getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { + const token = getTokenAtPosition(diag.file, diag.start!, /*includeJsDocComment*/ false); + const containingFunction = getContainingFunction(token); + const insertBefore = getNodeToInsertBefore(diag.file, containingFunction); + const returnType = getReturnTypeNode(containingFunction); + if (insertBefore) { + doChange(changes, context.sourceFile, insertBefore, returnType); + } + }), }); - function getNodeToInsertBefore(sourceFile: SourceFile, pos: number): Node | undefined { - const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); - const containingFunction = getContainingFunction(token); + function getReturnTypeNode(containingFunction: FunctionLike): TypeNode | undefined { + switch (containingFunction.kind) { + case SyntaxKind.MethodDeclaration: + case SyntaxKind.FunctionDeclaration: + return containingFunction.type; + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + if (isVariableDeclaration(containingFunction.parent) && + containingFunction.parent.type && + isFunctionTypeNode(containingFunction.parent.type)) { + return containingFunction.parent.type.type; + } + } + } + + function getNodeToInsertBefore(sourceFile: SourceFile, containingFunction: FunctionLike): Node | undefined { switch (containingFunction.kind) { case SyntaxKind.MethodDeclaration: return containingFunction.name; @@ -35,7 +58,13 @@ namespace ts.codefix { } } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, insertBefore: Node): void { + function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, insertBefore: Node, returnType: TypeNode | undefined): void { + if (returnType) { + const entityName = getEntityNameFromTypeNode(returnType); + if (!entityName || entityName.getText() !== "Promise") { + changes.replaceNode(sourceFile, returnType, createTypeReferenceNode("Promise", createNodeArray([returnType]))); + } + } changes.insertModifierBefore(sourceFile, SyntaxKind.AsyncKeyword, insertBefore); } } diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts new file mode 100644 index 0000000000000..4b172c3a1544c --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts @@ -0,0 +1,13 @@ +/// + +////const f: () => number | string = () => { +//// await Promise.resolve('foo'); +////} + +verify.codeFix({ + description: "Convert to async", + newFileContent: +`const f: () => Promise = async () => { + await Promise.resolve('foo'); +}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts new file mode 100644 index 0000000000000..bd46885ae449a --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts @@ -0,0 +1,14 @@ +/// + +////const f: string = () => { +//// await Promise.resolve('foo'); +////} + +// should not change type if it's incorrectly set +verify.codeFix({ + description: "Convert to async", + newFileContent: +`const f: string = async () => { + await Promise.resolve('foo'); +}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts new file mode 100644 index 0000000000000..2cbed427785ad --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts @@ -0,0 +1,13 @@ +/// + +////const f: () => Array = function() { +//// await Promise.resolve([]); +////} + +verify.codeFix({ + description: "Convert to async", + newFileContent: +`const f: () => Promise> = async function() { + await Promise.resolve([]); +}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts new file mode 100644 index 0000000000000..92e1addb88364 --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts @@ -0,0 +1,13 @@ +/// + +////const f: () => Promise = () => { +//// await Promise.resolve('foo'); +////} + +verify.codeFix({ + description: "Convert to async", + newFileContent: +`const f: () => Promise = async () => { + await Promise.resolve('foo'); +}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts new file mode 100644 index 0000000000000..8fe442c1fa4ee --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts @@ -0,0 +1,13 @@ +/// + +////function f(): number | string { +//// await Promise.resolve(8); +////} + +verify.codeFix({ + description: "Convert to async", + newFileContent: +`async function f(): Promise { + await Promise.resolve(8); +}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts new file mode 100644 index 0000000000000..ec2b5a3d6c103 --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts @@ -0,0 +1,17 @@ +/// + +////class Foo { +//// bar(): string { +//// await Promise.resolve('baz'); +//// } +////} + +verify.codeFix({ + description: "Convert to async", + newFileContent: +`class Foo { + async bar(): Promise { + await Promise.resolve('baz'); + } +}`, +}); From bbba931cb88cc54d4c78455a7fc4d3c55011c4ab Mon Sep 17 00:00:00 2001 From: Sharon Rolel Date: Tue, 9 Jan 2018 17:27:33 -0500 Subject: [PATCH 6/7] Review changes --- .../codefixes/fixAwaitInSyncFunction.ts | 70 ++++++++++--------- .../fourslash/codeFixAwaitInSyncFunction14.ts | 13 ++++ .../fourslash/codeFixAwaitInSyncFunction15.ts | 13 ++++ 3 files changed, 63 insertions(+), 33 deletions(-) create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts create mode 100644 tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts diff --git a/src/services/codefixes/fixAwaitInSyncFunction.ts b/src/services/codefixes/fixAwaitInSyncFunction.ts index 06884b12af3d4..ae5f52d0db4ef 100644 --- a/src/services/codefixes/fixAwaitInSyncFunction.ts +++ b/src/services/codefixes/fixAwaitInSyncFunction.ts @@ -9,59 +9,63 @@ namespace ts.codefix { errorCodes, getCodeActions(context) { const { sourceFile, span } = context; - const token = getTokenAtPosition(sourceFile, span.start, /*includeJsDocComment*/ false); - const containingFunction = getContainingFunction(token); - const insertBefore = getNodeToInsertBefore(sourceFile, containingFunction); - const returnType = getReturnTypeNode(containingFunction); - if (!insertBefore) return undefined; - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, insertBefore, returnType)); + const nodes = getNodes(sourceFile, span.start); + if (!nodes) return undefined; + const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, nodes)); return [{ description: getLocaleSpecificMessage(Diagnostics.Convert_to_async), changes, fixId }]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const token = getTokenAtPosition(diag.file, diag.start!, /*includeJsDocComment*/ false); - const containingFunction = getContainingFunction(token); - const insertBefore = getNodeToInsertBefore(diag.file, containingFunction); - const returnType = getReturnTypeNode(containingFunction); - if (insertBefore) { - doChange(changes, context.sourceFile, insertBefore, returnType); - } + const nodes = getNodes(diag.file, diag.start); + if (!nodes) return; + doChange(changes, context.sourceFile, nodes); }), }); - function getReturnTypeNode(containingFunction: FunctionLike): TypeNode | undefined { - switch (containingFunction.kind) { - case SyntaxKind.MethodDeclaration: - case SyntaxKind.FunctionDeclaration: - return containingFunction.type; - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - if (isVariableDeclaration(containingFunction.parent) && - containingFunction.parent.type && - isFunctionTypeNode(containingFunction.parent.type)) { - return containingFunction.parent.type.type; - } + function getReturnType(expr: FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction) { + if (expr.type) { + return expr.type; + } + if (isVariableDeclaration(expr.parent) && + expr.parent.type && + isFunctionTypeNode(expr.parent.type)) { + return expr.parent.type.type; } } - function getNodeToInsertBefore(sourceFile: SourceFile, containingFunction: FunctionLike): Node | undefined { + function getNodes(sourceFile: SourceFile, start: number): { insertBefore: Node, returnType: TypeNode | undefined } | undefined { + const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false); + const containingFunction = getContainingFunction(token); + let insertBefore: Node | undefined; switch (containingFunction.kind) { case SyntaxKind.MethodDeclaration: - return containingFunction.name; - case SyntaxKind.FunctionExpression: + insertBefore = containingFunction.name; + break; case SyntaxKind.FunctionDeclaration: - return findChildOfKind(containingFunction, SyntaxKind.FunctionKeyword, sourceFile); + case SyntaxKind.FunctionExpression: + insertBefore = findChildOfKind(containingFunction, SyntaxKind.FunctionKeyword, sourceFile); + break; case SyntaxKind.ArrowFunction: - return findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile) || first(containingFunction.parameters); + insertBefore = findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile) || first(containingFunction.parameters); + break; default: - return undefined; + return; } + + return { + insertBefore, + returnType: getReturnType(containingFunction) + }; } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, insertBefore: Node, returnType: TypeNode | undefined): void { + function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + { insertBefore, returnType }: { insertBefore: Node | undefined, returnType: TypeNode | undefined }): void { + if (returnType) { const entityName = getEntityNameFromTypeNode(returnType); - if (!entityName || entityName.getText() !== "Promise") { + if (!entityName || entityName.kind !== SyntaxKind.Identifier || entityName.text !== "Promise") { changes.replaceNode(sourceFile, returnType, createTypeReferenceNode("Promise", createNodeArray([returnType]))); } } diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts new file mode 100644 index 0000000000000..e7d3e771afdd4 --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts @@ -0,0 +1,13 @@ +/// + +////const f = function(): number { +//// await Promise.resolve(1); +////} + +verify.codeFix({ + description: "Convert to async", + newFileContent: +`const f = async function(): Promise { + await Promise.resolve(1); +}`, +}); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts new file mode 100644 index 0000000000000..81e3a7a0548e2 --- /dev/null +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts @@ -0,0 +1,13 @@ +/// + +////const f = (): number[] => { +//// await Promise.resolve([1]); +////} + +verify.codeFix({ + description: "Convert to async", + newFileContent: +`const f = async (): Promise => { + await Promise.resolve([1]); +}`, +}); From 752a9721d10ee9d47a09926aabd032b9805e4306 Mon Sep 17 00:00:00 2001 From: Sharon Rolel Date: Tue, 9 Jan 2018 18:09:22 -0500 Subject: [PATCH 7/7] Change codefix message --- src/compiler/diagnosticMessages.json | 2 +- src/services/codefixes/fixAwaitInSyncFunction.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction6.5.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts | 2 +- tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7a576556f71ee..d22193ab08d13 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3843,7 +3843,7 @@ "category": "Message", "code": 90028 }, - "Convert to async": { + "Add async modifier to containing function": { "category": "Message", "code": 90029 }, diff --git a/src/services/codefixes/fixAwaitInSyncFunction.ts b/src/services/codefixes/fixAwaitInSyncFunction.ts index ae5f52d0db4ef..883993e7b5146 100644 --- a/src/services/codefixes/fixAwaitInSyncFunction.ts +++ b/src/services/codefixes/fixAwaitInSyncFunction.ts @@ -12,7 +12,7 @@ namespace ts.codefix { const nodes = getNodes(sourceFile, span.start); if (!nodes) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, nodes)); - return [{ description: getLocaleSpecificMessage(Diagnostics.Convert_to_async), changes, fixId }]; + return [{ description: getLocaleSpecificMessage(Diagnostics.Add_async_modifier_to_containing_function), changes, fixId }]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts index bf5c50df83b80..e64d4072757a6 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction1.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `async function f() { await Promise.resolve(); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts index 4b172c3a1544c..42e0bc5be780f 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction10.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `const f: () => Promise = async () => { await Promise.resolve('foo'); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts index bd46885ae449a..bc7b17f8db5b4 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction11.ts @@ -6,7 +6,7 @@ // should not change type if it's incorrectly set verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `const f: string = async () => { await Promise.resolve('foo'); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts index 2cbed427785ad..ee694a80e9f26 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction12.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `const f: () => Promise> = async function() { await Promise.resolve([]); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts index 92e1addb88364..06f54d29eeb68 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction13.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `const f: () => Promise = async () => { await Promise.resolve('foo'); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts index e7d3e771afdd4..c798af5f5abd6 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction14.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `const f = async function(): Promise { await Promise.resolve(1); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts index 81e3a7a0548e2..a2c6f7dcb1ad9 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction15.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `const f = async (): Promise => { await Promise.resolve([1]); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts index f92320eaac7b5..e8da351af5d0a 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction2.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `const f = async function() { await Promise.resolve(); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts index 3533fa0545b43..a1c58b53831d4 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction5.ts @@ -7,7 +7,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `class Foo { async bar() { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction6.5.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction6.5.ts index f71f99e8f5123..c1b06811113ef 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction6.5.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction6.5.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `const f = async promise => { await promise; diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts index 79fc2f1fbdcce..0b0aa09816443 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction6.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `const f = async (promise) => { await promise; diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts index dab5d8640a114..a467e9ee0cef1 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction7.ts @@ -7,7 +7,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `async function f() { for await (const x of g()) { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts index 8fe442c1fa4ee..7c43add3edd21 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction8.ts @@ -5,7 +5,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `async function f(): Promise { await Promise.resolve(8); diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts index ec2b5a3d6c103..f93603e69c457 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction9.ts @@ -7,7 +7,7 @@ ////} verify.codeFix({ - description: "Convert to async", + description: "Add async modifier to containing function", newFileContent: `class Foo { async bar(): Promise {