Skip to content

Commit 5240f06

Browse files
authored
feat(52569): fixUnusedIdentifier: Unwanted side-effects when removing an unused destructuring declaration containing a function call (#52951)
1 parent 7e4592e commit 5240f06

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed

src/services/codefixes/fixUnusedIdentifier.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
CancellationToken,
44
cast,
55
CodeFixAction,
6+
CodeFixContext,
67
Debug,
78
DiagnosticAndArguments,
89
DiagnosticMessage,
@@ -14,12 +15,15 @@ import {
1415
forEach,
1516
FunctionLikeDeclaration,
1617
getJSDocParameterTags,
18+
getNewLineOrDefaultFromHost,
19+
getPrecedingNonSpaceCharacterPosition,
1720
getTokenAtPosition,
1821
Identifier,
1922
ImportDeclaration,
2023
isArrayBindingPattern,
2124
isBinaryExpression,
2225
isCallExpression,
26+
isCallLikeExpression,
2327
isComputedPropertyName,
2428
isDeclarationWithTypeParameterChildren,
2529
isExpressionStatement,
@@ -37,11 +41,14 @@ import {
3741
isPrefixUnaryExpression,
3842
isPropertyAccessExpression,
3943
isSuperKeyword,
44+
isVariableDeclaration,
4045
isVariableDeclarationList,
46+
length,
4147
map,
4248
Node,
4349
ObjectBindingPattern,
4450
ParameterDeclaration,
51+
probablyUsesSemicolons,
4552
Program,
4653
showModuleSpecifier,
4754
SourceFile,
@@ -114,7 +121,7 @@ registerCodeFix({
114121
}
115122
return [
116123
createDeleteFix(textChanges.ChangeTracker.with(context, t =>
117-
t.delete(sourceFile, token.parent.parent)), Diagnostics.Remove_unused_destructuring_declaration)
124+
deleteDestructuring(context, t, sourceFile, token.parent as ObjectBindingPattern | ArrayBindingPattern)), Diagnostics.Remove_unused_destructuring_declaration),
118125
];
119126
}
120127

@@ -243,6 +250,27 @@ function deleteDestructuringElements(changes: textChanges.ChangeTracker, sourceF
243250
forEach(node.elements, n => changes.delete(sourceFile, n));
244251
}
245252

253+
function deleteDestructuring(context: CodeFixContext, changes: textChanges.ChangeTracker, sourceFile: SourceFile, { parent }: ObjectBindingPattern | ArrayBindingPattern) {
254+
if (isVariableDeclaration(parent) && parent.initializer && isCallLikeExpression(parent.initializer)) {
255+
if (isVariableDeclarationList(parent.parent) && length(parent.parent.declarations) > 1) {
256+
const varStatement = parent.parent.parent;
257+
const pos = varStatement.getStart(sourceFile);
258+
const end = varStatement.end;
259+
changes.delete(sourceFile, parent);
260+
changes.insertNodeAt(sourceFile, end, parent.initializer, {
261+
prefix: getNewLineOrDefaultFromHost(context.host, context.formatContext.options) + sourceFile.text.slice(getPrecedingNonSpaceCharacterPosition(sourceFile.text, pos - 1), pos),
262+
suffix: probablyUsesSemicolons(sourceFile) ? ";" : "",
263+
});
264+
}
265+
else {
266+
changes.replaceNode(sourceFile, parent.parent, parent.initializer);
267+
}
268+
}
269+
else {
270+
changes.delete(sourceFile, parent);
271+
}
272+
}
273+
246274
function tryPrefixDeclaration(changes: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, token: Node): void {
247275
// Don't offer to prefix a property.
248276
if (errorCode === Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code) return;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @noUnusedLocals: true
4+
// @noUnusedParameters: true
5+
6+
////function foo() {
7+
//// return { a: 1 };
8+
////}
9+
////[|function bar() {
10+
//// const { a } = foo();
11+
////}|]
12+
13+
verify.codeFix({
14+
index: 0,
15+
description: ts.Diagnostics.Remove_unused_destructuring_declaration.message,
16+
newRangeContent:
17+
`function bar() {
18+
foo();
19+
}`,
20+
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @noUnusedLocals: true
4+
// @noUnusedParameters: true
5+
6+
////function foo() {
7+
//// return { a: 1 };
8+
////}
9+
////[|function bar() {
10+
//// const { a } = foo(),
11+
//// b = 1;
12+
//// return b;
13+
////}|]
14+
15+
verify.codeFix({
16+
index: 0,
17+
description: ts.Diagnostics.Remove_unused_destructuring_declaration.message,
18+
newRangeContent:
19+
`function bar() {
20+
const b = 1;
21+
foo();
22+
return b;
23+
}`,
24+
});

0 commit comments

Comments
 (0)