Skip to content

Commit ce5f707

Browse files
author
Arthur Ozga
committed
prefix identifiers
1 parent d9a68e3 commit ce5f707

File tree

2 files changed

+42
-26
lines changed

2 files changed

+42
-26
lines changed

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3621,6 +3621,10 @@
36213621
"category": "Message",
36223622
"code": 90024
36233623
},
3624+
"Prefix '{0}' with an underscore.": {
3625+
"category": "Message",
3626+
"code": 90025
3627+
},
36243628

36253629
"Convert function to an ES2015 class": {
36263630
"category": "Message",

src/services/codefixes/fixUnusedIdentifier.ts

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ namespace ts.codefix {
1818

1919
switch (token.kind) {
2020
case ts.SyntaxKind.Identifier:
21-
return deleteIdentifier();
21+
let actions = deleteIdentifier(<Identifier>token);
22+
(actions || (actions = [])).push(prefixIdentifierWithUnderscore(<Identifier>token));
23+
return actions;
2224

2325
case SyntaxKind.PropertyDeclaration:
2426
case SyntaxKind.NamespaceImport:
@@ -40,58 +42,68 @@ namespace ts.codefix {
4042
}
4143
}
4244

43-
function deleteIdentifier(): CodeAction[] | undefined {
44-
switch (token.parent.kind) {
45+
function prefixIdentifierWithUnderscore(identifier: Identifier): CodeAction {
46+
// TODO: make sure this work with prefixing trivia.
47+
const startPosition = identifier.getStart(sourceFile, /*includeJsDocComment*/ false);
48+
return {
49+
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Prefix_0_with_an_underscore), { 0: token.getText() }),
50+
changes: [{
51+
fileName: sourceFile.path,
52+
textChanges: [{
53+
span: { start: startPosition, length: 0 },
54+
newText: "_"
55+
}]
56+
}]
57+
};
58+
}
59+
60+
function deleteIdentifier(identifier: Identifier): CodeAction[] | undefined {
61+
const parent = identifier.parent;
62+
switch (parent.kind) {
4563
case ts.SyntaxKind.VariableDeclaration:
46-
return deleteVariableDeclaration(<ts.VariableDeclaration>token.parent);
64+
return deleteVariableDeclaration(<ts.VariableDeclaration>parent);
4765

4866
case SyntaxKind.TypeParameter:
49-
const typeParameters = (<DeclarationWithTypeParameters>token.parent.parent).typeParameters;
67+
const typeParameters = (<DeclarationWithTypeParameters>parent.parent).typeParameters;
5068
if (typeParameters.length === 1) {
5169
const previousToken = getTokenAtPosition(sourceFile, typeParameters.pos - 1, /*includeJsDocComment*/ false);
52-
if (!previousToken || previousToken.kind !== SyntaxKind.LessThanToken) {
53-
return deleteRange(typeParameters);
54-
}
5570
const nextToken = getTokenAtPosition(sourceFile, typeParameters.end, /*includeJsDocComment*/ false);
56-
if (!nextToken || nextToken.kind !== SyntaxKind.GreaterThanToken) {
57-
return deleteRange(typeParameters);
58-
}
71+
Debug.assert(previousToken.kind === SyntaxKind.LessThanToken);
72+
Debug.assert(nextToken.kind === SyntaxKind.GreaterThanToken);
73+
5974
return deleteNodeRange(previousToken, nextToken);
6075
}
6176
else {
62-
return deleteNodeInList(token.parent);
77+
return deleteNodeInList(parent);
6378
}
6479

6580
case ts.SyntaxKind.Parameter:
66-
const functionDeclaration = <FunctionDeclaration>token.parent.parent;
67-
if (functionDeclaration.parameters.length === 1) {
68-
return deleteNode(token.parent);
69-
}
70-
else {
71-
return deleteNodeInList(token.parent);
72-
}
81+
const functionDeclaration = <FunctionDeclaration>parent.parent;
82+
return functionDeclaration.parameters.length === 1 ?
83+
deleteNode(parent) :
84+
deleteNodeInList(parent);
7385

7486
// handle case where 'import a = A;'
7587
case SyntaxKind.ImportEqualsDeclaration:
76-
const importEquals = getAncestor(token, SyntaxKind.ImportEqualsDeclaration);
88+
const importEquals = getAncestor(identifier, SyntaxKind.ImportEqualsDeclaration);
7789
return deleteNode(importEquals);
7890

7991
case SyntaxKind.ImportSpecifier:
80-
const namedImports = <NamedImports>token.parent.parent;
92+
const namedImports = <NamedImports>parent.parent;
8193
if (namedImports.elements.length === 1) {
8294
// Only 1 import and it is unused. So the entire declaration should be removed.
83-
const importSpec = getAncestor(token, SyntaxKind.ImportDeclaration);
95+
const importSpec = getAncestor(identifier, SyntaxKind.ImportDeclaration);
8496
return deleteNode(importSpec);
8597
}
8698
else {
8799
// delete import specifier
88-
return deleteNodeInList(token.parent);
100+
return deleteNodeInList(parent);
89101
}
90102

91103
// handle case where "import d, * as ns from './file'"
92104
// or "'import {a, b as ns} from './file'"
93105
case SyntaxKind.ImportClause: // this covers both 'import |d|' and 'import |d,| *'
94-
const importClause = <ImportClause>token.parent;
106+
const importClause = <ImportClause>parent;
95107
if (!importClause.namedBindings) { // |import d from './file'| or |import * as ns from './file'|
96108
const importDecl = getAncestor(importClause, SyntaxKind.ImportDeclaration);
97109
return deleteNode(importDecl);
@@ -110,8 +122,8 @@ namespace ts.codefix {
110122
}
111123

112124
case SyntaxKind.NamespaceImport:
113-
const namespaceImport = <NamespaceImport>token.parent;
114-
if (namespaceImport.name === token && !(<ImportClause>namespaceImport.parent).name) {
125+
const namespaceImport = <NamespaceImport>parent;
126+
if (namespaceImport.name === identifier && !(<ImportClause>namespaceImport.parent).name) {
115127
const importDecl = getAncestor(namespaceImport, SyntaxKind.ImportDeclaration);
116128
return deleteNode(importDecl);
117129
}

0 commit comments

Comments
 (0)