Skip to content

Commit 8b6a887

Browse files
authored
fix(32297): add quick-fix action to delete parameter destructuring elements (microsoft#38764)
1 parent a812a74 commit 8b6a887

13 files changed

+86
-47
lines changed

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5155,10 +5155,6 @@
51555155
"category": "Message",
51565156
"code": 90008
51575157
},
5158-
"Remove destructuring": {
5159-
"category": "Message",
5160-
"code": 90009
5161-
},
51625158
"Remove variable statement": {
51635159
"category": "Message",
51645160
"code": 90010
@@ -5275,6 +5271,14 @@
52755271
"category": "Message",
52765272
"code": 90038
52775273
},
5274+
"Remove unused destructuring declaration": {
5275+
"category": "Message",
5276+
"code": 90039
5277+
},
5278+
"Remove unused declarations for: '{0}'": {
5279+
"category": "Message",
5280+
"code": 90041
5281+
},
52785282
"Declare a private field named '{0}'.": {
52795283
"category": "Message",
52805284
"code": 90053

src/services/codefixes/fixUnusedIdentifier.ts

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,33 @@ namespace ts.codefix {
3434
const changes = textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, importDecl));
3535
return [createDeleteFix(changes, [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)])];
3636
}
37-
const delDestructure = textChanges.ChangeTracker.with(context, t =>
38-
tryDeleteFullDestructure(token, t, sourceFile, checker, sourceFiles, /*isFixAll*/ false));
39-
if (delDestructure.length) {
40-
return [createDeleteFix(delDestructure, Diagnostics.Remove_destructuring)];
37+
38+
if (isObjectBindingPattern(token.parent)) {
39+
if (isParameter(token.parent.parent)) {
40+
const elements = token.parent.elements;
41+
const diagnostic: [DiagnosticMessage, string] = [
42+
elements.length > 1 ? Diagnostics.Remove_unused_declarations_for_Colon_0 : Diagnostics.Remove_unused_declaration_for_Colon_0,
43+
map(elements, e => e.getText(sourceFile)).join(", ")
44+
];
45+
return [
46+
createDeleteFix(textChanges.ChangeTracker.with(context, t =>
47+
deleteDestructuringElements(t, sourceFile, <ObjectBindingPattern>token.parent)), diagnostic)
48+
];
49+
}
50+
return [
51+
createDeleteFix(textChanges.ChangeTracker.with(context, t =>
52+
t.delete(sourceFile, token.parent.parent)), Diagnostics.Remove_unused_destructuring_declaration)
53+
];
4154
}
42-
const delVar = textChanges.ChangeTracker.with(context, t => tryDeleteFullVariableStatement(sourceFile, token, t));
43-
if (delVar.length) {
44-
return [createDeleteFix(delVar, Diagnostics.Remove_variable_statement)];
55+
56+
if (canDeleteEntireVariableStatement(sourceFile, token)) {
57+
return [
58+
createDeleteFix(textChanges.ChangeTracker.with(context, t =>
59+
deleteEntireVariableStatement(t, sourceFile, <VariableDeclarationList>token.parent)), Diagnostics.Remove_variable_statement)
60+
];
4561
}
4662

4763
const result: CodeFixAction[] = [];
48-
4964
if (token.kind === SyntaxKind.InferKeyword) {
5065
const changes = textChanges.ChangeTracker.with(context, t => changeInferToUnknown(t, sourceFile, token));
5166
const name = cast(token.parent, isInferTypeNode).typeParameter.name.text;
@@ -79,7 +94,9 @@ namespace ts.codefix {
7994
tryPrefixDeclaration(changes, diag.code, sourceFile, token);
8095
break;
8196
case fixIdDelete: {
82-
if (token.kind === SyntaxKind.InferKeyword) break; // Can't delete
97+
if (token.kind === SyntaxKind.InferKeyword) {
98+
break; // Can't delete
99+
}
83100
const importDecl = tryGetFullImport(token);
84101
if (importDecl) {
85102
changes.delete(sourceFile, importDecl);
@@ -90,8 +107,18 @@ namespace ts.codefix {
90107
else if (token.kind === SyntaxKind.LessThanToken) {
91108
deleteTypeParameters(changes, sourceFile, token);
92109
}
93-
else if (!tryDeleteFullDestructure(token, changes, sourceFile, checker, sourceFiles, /*isFixAll*/ true) &&
94-
!tryDeleteFullVariableStatement(sourceFile, token, changes)) {
110+
else if (isObjectBindingPattern(token.parent)) {
111+
if (isParameter(token.parent.parent)) {
112+
deleteDestructuringElements(changes, sourceFile, token.parent);
113+
}
114+
else {
115+
changes.delete(sourceFile, token.parent.parent);
116+
}
117+
}
118+
else if (canDeleteEntireVariableStatement(sourceFile, token)) {
119+
deleteEntireVariableStatement(changes, sourceFile, <VariableDeclarationList>token.parent);
120+
}
121+
else {
95122
tryDeleteDeclaration(sourceFile, token, changes, checker, sourceFiles, /*isFixAll*/ true);
96123
}
97124
break;
@@ -125,25 +152,16 @@ namespace ts.codefix {
125152
return token.kind === SyntaxKind.ImportKeyword ? tryCast(token.parent, isImportDeclaration) : undefined;
126153
}
127154

128-
function tryDeleteFullDestructure(token: Node, changes: textChanges.ChangeTracker, sourceFile: SourceFile, checker: TypeChecker, sourceFiles: readonly SourceFile[], isFixAll: boolean): boolean {
129-
if (token.kind !== SyntaxKind.OpenBraceToken || !isObjectBindingPattern(token.parent)) return false;
130-
const decl = token.parent.parent;
131-
if (decl.kind === SyntaxKind.Parameter) {
132-
tryDeleteParameter(changes, sourceFile, decl, checker, sourceFiles, isFixAll);
133-
}
134-
else {
135-
changes.delete(sourceFile, decl);
136-
}
137-
return true;
155+
function canDeleteEntireVariableStatement(sourceFile: SourceFile, token: Node): boolean {
156+
return isVariableDeclarationList(token.parent) && first(token.parent.getChildren(sourceFile)) === token;
138157
}
139158

140-
function tryDeleteFullVariableStatement(sourceFile: SourceFile, token: Node, changes: textChanges.ChangeTracker): boolean {
141-
const declarationList = tryCast(token.parent, isVariableDeclarationList);
142-
if (declarationList && declarationList.getChildren(sourceFile)[0] === token) {
143-
changes.delete(sourceFile, declarationList.parent.kind === SyntaxKind.VariableStatement ? declarationList.parent : declarationList);
144-
return true;
145-
}
146-
return false;
159+
function deleteEntireVariableStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: VariableDeclarationList) {
160+
changes.delete(sourceFile, node.parent.kind === SyntaxKind.VariableStatement ? node.parent : node);
161+
}
162+
163+
function deleteDestructuringElements(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: ObjectBindingPattern) {
164+
forEach(node.elements, n => changes.delete(sourceFile, n));
147165
}
148166

149167
function tryPrefixDeclaration(changes: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, token: Node): void {
@@ -205,7 +223,7 @@ namespace ts.codefix {
205223
}
206224
}
207225

208-
function tryDeleteParameter(changes: textChanges.ChangeTracker, sourceFile: SourceFile, p: ParameterDeclaration, checker: TypeChecker, sourceFiles: readonly SourceFile[], isFixAll: boolean): void {
226+
function tryDeleteParameter(changes: textChanges.ChangeTracker, sourceFile: SourceFile, p: ParameterDeclaration, checker: TypeChecker, sourceFiles: readonly SourceFile[], isFixAll = false): void {
209227
if (mayDeleteParameter(p, checker, isFixAll)) {
210228
if (p.modifiers && p.modifiers.length > 0
211229
&& (!isIdentifier(p.name) || FindAllReferences.Core.isSymbolReferencedInFile(p.name, checker, sourceFile))) {

tests/cases/fourslash/codeFixUnusedIdentifier_all_delete.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050

5151
verify.codeFixAll({
5252
fixId: "unusedIdentifier_delete",
53-
fixAllDescription: "Delete all unused declarations",
53+
fixAllDescription: ts.Diagnostics.Delete_all_unused_declarations.message,
5454
newFileContent:
5555
`import { used1 } from "foo";
5656
import { used2 } from "foo";

tests/cases/fourslash/codeFixUnusedIdentifier_all_delete_js.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
verify.codeFixAll({
4040
fixId: "unusedIdentifier_delete",
41-
fixAllDescription: "Delete all unused declarations",
41+
fixAllDescription: ts.Diagnostics.Delete_all_unused_declarations.message,
4242
newFileContent:
4343
`/** Parameter doc comment */
4444
function f() {}

tests/cases/fourslash/codeFixUnusedIdentifier_all_delete_paramInFunction.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55

66
verify.codeFixAll({
77
fixId: "unusedIdentifier_delete",
8-
fixAllDescription: "Delete all unused declarations",
8+
fixAllDescription: ts.Diagnostics.Delete_all_unused_declarations.message,
99
newFileContent: "export {};\n",
1010
});

tests/cases/fourslash/codeFixUnusedIdentifier_deleteWrite.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
verify.codeFixAll({
1616
fixId: "unusedIdentifier_delete",
17-
fixAllDescription: "Delete all unused declarations",
17+
fixAllDescription: ts.Diagnostics.Delete_all_unused_declarations.message,
1818
newFileContent:
1919
`
2020
export class C {

tests/cases/fourslash/codeFixUnusedIdentifier_destructure_allUnused.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
////const { x, y } = o;
88

99
verify.codeFix({
10-
description: "Remove destructuring",
10+
description: ts.Diagnostics.Remove_unused_destructuring_declaration.message,
1111
newFileContent:
1212
`export {};
1313
`,

tests/cases/fourslash/codeFixUnusedIdentifier_destructure_allUnused_all.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212

1313
verify.codeFixAll({
1414
fixId: "unusedIdentifier_delete",
15-
fixAllDescription: "Delete all unused declarations",
15+
fixAllDescription: ts.Diagnostics.Delete_all_unused_declarations.message,
1616
newFileContent:
1717
`const { a } = o;
1818
a;
19-
export function f({ a }) {
19+
export function f({ a }, { }) {
2020
a;
2121
}`,
2222
});

tests/cases/fourslash/codeFixUnusedIdentifier_destructure_allUnused_for.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
////for (const { x } of o) {}
77

88
verify.codeFix({
9-
description: "Remove destructuring",
9+
description: ts.Diagnostics.Remove_unused_destructuring_declaration.message,
1010
newFileContent:
1111
`for (const {} of o) {}`,
1212
});

tests/cases/fourslash/codeFixUnusedIdentifier_destructure_allUnused_nested.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
////const { x: { a, b } } = o;
88

99
verify.codeFix({
10-
description: "Remove destructuring",
10+
description: ts.Diagnostics.Remove_unused_destructuring_declaration.message,
1111
newFileContent:
1212
`export {};
1313
const { } = o;`,

0 commit comments

Comments
 (0)