diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 6196191328016..078bd600771d4 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4261,5 +4261,13 @@ "Add missing typeof": { "category": "Message", "code": 95052 + }, + "Remove unused label": { + "category": "Message", + "code": 95053 + }, + "Remove all unused labels": { + "category": "Message", + "code": 95054 } } diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 4fb96dbe93dc1..359701a02cb3a 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -106,6 +106,7 @@ "../services/codefixes/fixForgottenThisPropertyAccess.ts", "../services/codefixes/fixUnusedIdentifier.ts", "../services/codefixes/fixUnreachableCode.ts", + "../services/codefixes/fixUnusedLabel.ts", "../services/codefixes/fixJSDocTypes.ts", "../services/codefixes/fixAwaitInSyncFunction.ts", "../services/codefixes/disableJsDiagnostics.ts", diff --git a/src/server/tsconfig.json b/src/server/tsconfig.json index 50e06eb3f2339..8ae6974baf062 100644 --- a/src/server/tsconfig.json +++ b/src/server/tsconfig.json @@ -102,6 +102,7 @@ "../services/codefixes/fixForgottenThisPropertyAccess.ts", "../services/codefixes/fixUnusedIdentifier.ts", "../services/codefixes/fixUnreachableCode.ts", + "../services/codefixes/fixUnusedLabel.ts", "../services/codefixes/fixJSDocTypes.ts", "../services/codefixes/fixAwaitInSyncFunction.ts", "../services/codefixes/disableJsDiagnostics.ts", diff --git a/src/server/tsconfig.library.json b/src/server/tsconfig.library.json index 43e8fd1857b9a..922af11e87963 100644 --- a/src/server/tsconfig.library.json +++ b/src/server/tsconfig.library.json @@ -108,6 +108,7 @@ "../services/codefixes/fixForgottenThisPropertyAccess.ts", "../services/codefixes/fixUnusedIdentifier.ts", "../services/codefixes/fixUnreachableCode.ts", + "../services/codefixes/fixUnusedLabel.ts", "../services/codefixes/fixJSDocTypes.ts", "../services/codefixes/fixAwaitInSyncFunction.ts", "../services/codefixes/disableJsDiagnostics.ts", diff --git a/src/services/codefixes/fixUnusedLabel.ts b/src/services/codefixes/fixUnusedLabel.ts new file mode 100644 index 0000000000000..b99f72d68397e --- /dev/null +++ b/src/services/codefixes/fixUnusedLabel.ts @@ -0,0 +1,25 @@ +/* @internal */ +namespace ts.codefix { + const fixId = "fixUnusedLabel"; + const errorCodes = [Diagnostics.Unused_label.code]; + registerCodeFix({ + errorCodes, + getCodeActions(context) { + const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start)); + return [createCodeFixAction(fixId, changes, Diagnostics.Remove_unused_label, fixId, Diagnostics.Remove_all_unused_labels)]; + }, + fixIds: [fixId], + getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start)), + }); + + function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number): void { + const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false); + const labeledStatement = cast(token.parent, isLabeledStatement); + const pos = token.getStart(sourceFile); + const statementPos = labeledStatement.statement.getStart(sourceFile); + // If label is on a separate line, just delete the rest of that line, but not the indentation of the labeled statement. + const end = positionsAreOnSameLine(pos, statementPos, sourceFile) ? statementPos + : skipTrivia(sourceFile.text, findChildOfKind(labeledStatement, SyntaxKind.ColonToken, sourceFile)!.end, /*stopAfterLineBreak*/ true); + changes.deleteRange(sourceFile, { pos, end }); + } +} diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index d78086504c926..7e1ccc9c3afc0 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -99,6 +99,7 @@ "codefixes/fixForgottenThisPropertyAccess.ts", "codefixes/fixUnusedIdentifier.ts", "codefixes/fixUnreachableCode.ts", + "codefixes/fixUnusedLabel.ts", "codefixes/fixJSDocTypes.ts", "codefixes/fixAwaitInSyncFunction.ts", "codefixes/disableJsDiagnostics.ts", diff --git a/tests/cases/fourslash/codeFixUnusedLabel.ts b/tests/cases/fourslash/codeFixUnusedLabel.ts new file mode 100644 index 0000000000000..0feea173b0c2b --- /dev/null +++ b/tests/cases/fourslash/codeFixUnusedLabel.ts @@ -0,0 +1,11 @@ +/// + +// @noUnusedLocals: true + +/////* a */label/* b */:/* c */while (1) {} + +verify.codeFix({ + description: "Remove unused label", + newFileContent: +`/* a */while (1) {}`, +}); diff --git a/tests/cases/fourslash/codeFixUnusedLabel_all.ts b/tests/cases/fourslash/codeFixUnusedLabel_all.ts new file mode 100644 index 0000000000000..2769e0a65eed9 --- /dev/null +++ b/tests/cases/fourslash/codeFixUnusedLabel_all.ts @@ -0,0 +1,21 @@ +/// + +// @noUnusedLocals: true + +////label1: while (1) {} +//// +////function f() { +////label2: +//// while (1) {} +////} + +verify.codeFixAll({ + fixId: "fixUnusedLabel", + fixAllDescription: "Remove all unused labels", + newFileContent: +`while (1) {} + +function f() { + while (1) {} +}`, +});