Skip to content

Commit 899e2d0

Browse files
authored
fix(40469): suggest QF convert 'Convert to named function' to function expressions (#40476)
1 parent 98aaeb7 commit 899e2d0

3 files changed

+27
-20
lines changed

src/services/refactors/convertArrowFunctionOrFunctionExpression.ts

+19-12
Original file line numberDiff line numberDiff line change
@@ -112,20 +112,20 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression {
112112

113113
function getFunctionInfo(file: SourceFile, startPosition: number, program: Program): FunctionInfo | undefined {
114114
const token = getTokenAtPosition(file, startPosition);
115-
116-
const arrowFunc = getArrowFunctionFromVariableDeclaration(token.parent);
117-
if (arrowFunc && !containingThis(arrowFunc.body)) return { selectedVariableDeclaration: true, func: arrowFunc };
118-
119-
const maybeFunc = getContainingFunction(token);
120115
const typeChecker = program.getTypeChecker();
116+
const func = tryGetFunctionFromVariableDeclaration(file, typeChecker, token.parent);
117+
if (func && !containingThis(func.body)) {
118+
return { selectedVariableDeclaration: true, func };
119+
}
121120

121+
const maybeFunc = getContainingFunction(token);
122122
if (
123123
maybeFunc &&
124124
(isFunctionExpression(maybeFunc) || isArrowFunction(maybeFunc)) &&
125125
!rangeContainsRange(maybeFunc.body, token) &&
126126
!containingThis(maybeFunc.body)
127127
) {
128-
if ((isFunctionExpression(maybeFunc) && maybeFunc.name && FindAllReferences.Core.isSymbolReferencedInFile(maybeFunc.name, typeChecker, file))) return undefined;
128+
if (isFunctionExpression(maybeFunc) && isFunctionReferencedInFile(file, typeChecker, maybeFunc)) return undefined;
129129
return { selectedVariableDeclaration: false, func: maybeFunc };
130130
}
131131

@@ -136,13 +136,16 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression {
136136
return isVariableDeclaration(parent) || (isVariableDeclarationList(parent) && parent.declarations.length === 1);
137137
}
138138

139-
function getArrowFunctionFromVariableDeclaration(parent: Node): ArrowFunction | undefined {
140-
if (!isSingleVariableDeclaration(parent)) return undefined;
141-
const variableDeclaration = isVariableDeclaration(parent) ? parent : parent.declarations[0];
142-
139+
function tryGetFunctionFromVariableDeclaration(sourceFile: SourceFile, typeChecker: TypeChecker, parent: Node): ArrowFunction | FunctionExpression | undefined {
140+
if (!isSingleVariableDeclaration(parent)) {
141+
return undefined;
142+
}
143+
const variableDeclaration = isVariableDeclaration(parent) ? parent : first(parent.declarations);
143144
const initializer = variableDeclaration.initializer;
144-
if (!initializer || !isArrowFunction(initializer)) return undefined;
145-
return initializer;
145+
if (initializer && (isArrowFunction(initializer) || isFunctionExpression(initializer) && !isFunctionReferencedInFile(sourceFile, typeChecker, initializer))) {
146+
return initializer;
147+
}
148+
return undefined;
146149
}
147150

148151
function convertToBlock(body: ConciseBody): Block {
@@ -213,4 +216,8 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression {
213216
function canBeConvertedToExpression(body: Block, head: Statement): head is ReturnStatement {
214217
return body.statements.length === 1 && ((isReturnStatement(head) && !!head.expression));
215218
}
219+
220+
function isFunctionReferencedInFile(sourceFile: SourceFile, typeChecker: TypeChecker, node: FunctionExpression): boolean {
221+
return !!node.name && FindAllReferences.Core.isSymbolReferencedInFile(node.name, typeChecker, sourceFile);
222+
}
216223
}

tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
//// /*z*/c/*y*/onst /*x*/f/*w*/oo = /*v*/f/*u*/unction() /*t*/{/*s*/ /*r*/r/*q*/eturn 42;};
44

55
goTo.select("z", "y");
6-
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
76
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
8-
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
7+
verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
8+
verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
99

1010
goTo.select("x", "w");
11-
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
1211
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
13-
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
12+
verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
13+
verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
1414

1515
goTo.select("v", "u");
1616
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");

tests/cases/fourslash/refactorConvertArrowFunctionOrFunctionExpression_Availability_Anon_unusedName.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
//// /*z*/c/*y*/onst /*x*/f/*w*/oo = /*v*/f/*u*/unction bar() /*t*/{/*s*/ /*r*/r/*q*/eturn 42;};
44

55
goTo.select("z", "y");
6-
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
76
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
8-
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
7+
verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
8+
verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
99

1010
goTo.select("x", "w");
11-
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
1211
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to anonymous function");
13-
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
12+
verify.refactorAvailable("Convert arrow function or function expression", "Convert to named function");
13+
verify.refactorAvailable("Convert arrow function or function expression", "Convert to arrow function");
1414

1515
goTo.select("v", "u");
1616
verify.not.refactorAvailable("Convert arrow function or function expression", "Convert to named function");

0 commit comments

Comments
 (0)