diff --git a/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts index 6982d67f0d452..c9ef923534f7d 100644 --- a/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts +++ b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts @@ -112,20 +112,20 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { function getFunctionInfo(file: SourceFile, startPosition: number, program: Program): FunctionInfo | undefined { const token = getTokenAtPosition(file, startPosition); - - const arrowFunc = getArrowFunctionFromVariableDeclaration(token.parent); - if (arrowFunc && !containingThis(arrowFunc.body)) return { selectedVariableDeclaration: true, func: arrowFunc }; - - const maybeFunc = getContainingFunction(token); const typeChecker = program.getTypeChecker(); + const func = tryGetFunctionFromVariableDeclaration(file, typeChecker, token.parent); + if (func && !containingThis(func.body)) { + return { selectedVariableDeclaration: true, func }; + } + const maybeFunc = getContainingFunction(token); if ( maybeFunc && (isFunctionExpression(maybeFunc) || isArrowFunction(maybeFunc)) && !rangeContainsRange(maybeFunc.body, token) && !containingThis(maybeFunc.body) ) { - if ((isFunctionExpression(maybeFunc) && maybeFunc.name && FindAllReferences.Core.isSymbolReferencedInFile(maybeFunc.name, typeChecker, file))) return undefined; + if (isFunctionExpression(maybeFunc) && isFunctionReferencedInFile(file, typeChecker, maybeFunc)) return undefined; return { selectedVariableDeclaration: false, func: maybeFunc }; } @@ -136,13 +136,16 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { return isVariableDeclaration(parent) || (isVariableDeclarationList(parent) && parent.declarations.length === 1); } - function getArrowFunctionFromVariableDeclaration(parent: Node): ArrowFunction | undefined { - if (!isSingleVariableDeclaration(parent)) return undefined; - const variableDeclaration = isVariableDeclaration(parent) ? parent : parent.declarations[0]; - + function tryGetFunctionFromVariableDeclaration(sourceFile: SourceFile, typeChecker: TypeChecker, parent: Node): ArrowFunction | FunctionExpression | undefined { + if (!isSingleVariableDeclaration(parent)) { + return undefined; + } + const variableDeclaration = isVariableDeclaration(parent) ? parent : first(parent.declarations); const initializer = variableDeclaration.initializer; - if (!initializer || !isArrowFunction(initializer)) return undefined; - return initializer; + if (initializer && (isArrowFunction(initializer) || isFunctionExpression(initializer) && !isFunctionReferencedInFile(sourceFile, typeChecker, initializer))) { + return initializer; + } + return undefined; } function convertToBlock(body: ConciseBody): Block { @@ -213,4 +216,8 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression { function canBeConvertedToExpression(body: Block, head: Statement): head is ReturnStatement { return body.statements.length === 1 && ((isReturnStatement(head) && !!head.expression)); } + + function isFunctionReferencedInFile(sourceFile: SourceFile, typeChecker: TypeChecker, node: FunctionExpression): boolean { + return !!node.name && FindAllReferences.Core.isSymbolReferencedInFile(node.name, typeChecker, sourceFile); + } } diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon.ts index 0fa3222617c1b..0d42ca680f56b 100644 --- a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon.ts +++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon.ts @@ -3,14 +3,14 @@ //// /*z*/c/*y*/onst /*x*/f/*w*/oo = /*v*/f/*u*/unction() /*t*/{/*s*/ /*r*/r/*q*/eturn 42;}; goTo.select("z", "y"); -verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function"); verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function"); -verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function"); +verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function"); +verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function"); goTo.select("x", "w"); -verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function"); verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function"); -verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function"); +verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function"); +verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function"); goTo.select("v", "u"); verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function"); diff --git a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_unusedName.ts b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_unusedName.ts index 480dd466ec24a..eee97141859e4 100644 --- a/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_unusedName.ts +++ b/tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_unusedName.ts @@ -3,14 +3,14 @@ //// /*z*/c/*y*/onst /*x*/f/*w*/oo = /*v*/f/*u*/unction bar() /*t*/{/*s*/ /*r*/r/*q*/eturn 42;}; goTo.select("z", "y"); -verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function"); verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function"); -verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function"); +verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function"); +verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function"); goTo.select("x", "w"); -verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function"); verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function"); -verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function"); +verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function"); +verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function"); goTo.select("v", "u"); verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");