1
+ /* @internal */
2
+ namespace ts . codefix {
3
+ registerCodeFix ( {
4
+ errorCodes : [
5
+ Diagnostics . _0_is_declared_but_never_used . code ,
6
+ Diagnostics . Property_0_is_declared_but_never_used . code
7
+ ] ,
8
+ getCodeActions : ( context : CodeFixContext ) => {
9
+ const sourceFile = context . sourceFile ;
10
+ const start = context . span . start ;
11
+
12
+ let token = getTokenAtPosition ( sourceFile , start ) ;
13
+
14
+ // this handles var ["computed"] = 12;
15
+ if ( token . kind === SyntaxKind . OpenBracketToken ) {
16
+ token = getTokenAtPosition ( sourceFile , start + 1 ) ;
17
+ }
18
+
19
+ switch ( token . kind ) {
20
+ case ts . SyntaxKind . Identifier :
21
+ switch ( token . parent . kind ) {
22
+ case ts . SyntaxKind . VariableDeclaration :
23
+ switch ( token . parent . parent . parent . kind ) {
24
+ case SyntaxKind . ForStatement :
25
+ const forStatement = < ForStatement > token . parent . parent . parent ;
26
+ const forInitializer = < VariableDeclarationList > forStatement . initializer ;
27
+ if ( forInitializer . declarations . length === 1 ) {
28
+ return createCodeFix ( "" , forInitializer . pos , forInitializer . end - forInitializer . pos ) ;
29
+ }
30
+ else {
31
+ return removeSingleItem ( forInitializer . declarations , token ) ;
32
+ }
33
+
34
+ case SyntaxKind . ForOfStatement :
35
+ const forOfStatement = < ForOfStatement > token . parent . parent . parent ;
36
+ if ( forOfStatement . initializer . kind === SyntaxKind . VariableDeclarationList ) {
37
+ const forOfInitializer = < VariableDeclarationList > forOfStatement . initializer ;
38
+ return createCodeFix ( "{}" , forOfInitializer . declarations [ 0 ] . pos , forOfInitializer . declarations [ 0 ] . end - forOfInitializer . declarations [ 0 ] . pos ) ;
39
+ }
40
+ break ;
41
+
42
+ case SyntaxKind . ForInStatement :
43
+ // There is no valid fix in the case of:
44
+ // for .. in
45
+ return undefined ;
46
+
47
+ case SyntaxKind . CatchClause :
48
+ const catchClause = < CatchClause > token . parent . parent ;
49
+ const parameter = catchClause . variableDeclaration . getChildren ( ) [ 0 ] ;
50
+ return createCodeFix ( "" , parameter . pos , parameter . end - parameter . pos ) ;
51
+
52
+ default :
53
+ const variableStatement = < VariableStatement > token . parent . parent . parent ;
54
+ if ( variableStatement . declarationList . declarations . length === 1 ) {
55
+ return createCodeFix ( "" , variableStatement . pos , variableStatement . end - variableStatement . pos ) ;
56
+ }
57
+ else {
58
+ const declarations = variableStatement . declarationList . declarations ;
59
+ return removeSingleItem ( declarations , token ) ;
60
+ }
61
+ }
62
+
63
+ case SyntaxKind . TypeParameter :
64
+ const typeParameters = ( < DeclarationWithTypeParameters > token . parent . parent ) . typeParameters ;
65
+ if ( typeParameters . length === 1 ) {
66
+ return createCodeFix ( "" , token . parent . pos - 1 , token . parent . end - token . parent . pos + 2 ) ;
67
+ }
68
+ else {
69
+ return removeSingleItem ( typeParameters , token ) ;
70
+ }
71
+
72
+ case ts . SyntaxKind . Parameter :
73
+ const functionDeclaration = < FunctionDeclaration > token . parent . parent ;
74
+ if ( functionDeclaration . parameters . length === 1 ) {
75
+ return createCodeFix ( "" , token . parent . pos , token . parent . end - token . parent . pos ) ;
76
+ }
77
+ else {
78
+ return removeSingleItem ( functionDeclaration . parameters , token ) ;
79
+ }
80
+
81
+ // handle case where 'import a = A;'
82
+ case SyntaxKind . ImportEqualsDeclaration :
83
+ const importEquals = findImportDeclaration ( token ) ;
84
+ return createCodeFix ( "" , importEquals . pos , importEquals . end - importEquals . pos ) ;
85
+
86
+ case SyntaxKind . ImportSpecifier :
87
+ const namedImports = < NamedImports > token . parent . parent ;
88
+ if ( namedImports . elements . length === 1 ) {
89
+ // Only 1 import and it is unused. So the entire declaration should be removed.
90
+ const importSpec = findImportDeclaration ( token ) ;
91
+ return createCodeFix ( "" , importSpec . pos , importSpec . end - importSpec . pos ) ;
92
+ }
93
+ else {
94
+ return removeSingleItem ( namedImports . elements , token ) ;
95
+ }
96
+
97
+ // handle case where "import d, * as ns from './file'"
98
+ // or "'import {a, b as ns} from './file'"
99
+ case SyntaxKind . ImportClause : // this covers both 'import |d|' and 'import |d,| *'
100
+ const importClause = < ImportClause > token . parent ;
101
+ if ( ! importClause . namedBindings ) { // |import d from './file'| or |import * as ns from './file'|
102
+ const importDecl = findImportDeclaration ( importClause ) ;
103
+ return createCodeFix ( "" , importDecl . pos , importDecl . end - importDecl . pos ) ;
104
+ }
105
+ else { // import |d,| * as ns from './file'
106
+ return createCodeFix ( "" , importClause . name . pos , importClause . namedBindings . pos - importClause . name . pos ) ;
107
+ }
108
+
109
+ case SyntaxKind . NamespaceImport :
110
+ const namespaceImport = < NamespaceImport > token . parent ;
111
+ if ( namespaceImport . name == token && ! ( < ImportClause > namespaceImport . parent ) . name ) {
112
+ const importDecl = findImportDeclaration ( namespaceImport ) ;
113
+ return createCodeFix ( "" , importDecl . pos , importDecl . end - importDecl . pos ) ;
114
+ }
115
+ else {
116
+ const start = ( < ImportClause > namespaceImport . parent ) . name . end ;
117
+ return createCodeFix ( "" , start , ( < ImportClause > namespaceImport . parent ) . namedBindings . end - start ) ;
118
+ }
119
+ }
120
+ break ;
121
+
122
+ case SyntaxKind . PropertyDeclaration :
123
+ return createCodeFix ( "" , token . parent . pos , token . parent . end - token . parent . pos ) ;
124
+
125
+ case SyntaxKind . NamespaceImport :
126
+ return createCodeFix ( "" , token . parent . pos , token . parent . end - token . parent . pos ) ;
127
+ }
128
+ if ( isDeclarationName ( token ) ) {
129
+ return createCodeFix ( "" , token . parent . pos , token . parent . end - token . parent . pos ) ;
130
+ }
131
+ else if ( isLiteralComputedPropertyDeclarationName ( token ) ) {
132
+ return createCodeFix ( "" , token . parent . parent . pos , token . parent . parent . end - token . parent . parent . pos ) ;
133
+ }
134
+ else {
135
+ return undefined ;
136
+ }
137
+
138
+ function findImportDeclaration ( token : Node ) : Node {
139
+ let importDecl = token ;
140
+ while ( importDecl . kind != SyntaxKind . ImportDeclaration && importDecl . parent ) {
141
+ importDecl = importDecl . parent ;
142
+ }
143
+
144
+ return importDecl ;
145
+ }
146
+
147
+ function createCodeFix ( newText : string , start : number , length : number ) : CodeAction [ ] {
148
+ return [ {
149
+ description : getLocaleSpecificMessage ( Diagnostics . Remove_unused_identifiers ) ,
150
+ changes : [ {
151
+ fileName : sourceFile . fileName ,
152
+ textChanges : [ { newText, span : { start, length } } ]
153
+ } ]
154
+ } ] ;
155
+ }
156
+
157
+ function removeSingleItem < T extends Node > ( elements : NodeArray < T > , token : T ) : CodeAction [ ] {
158
+ if ( elements [ 0 ] === token . parent ) {
159
+ return createCodeFix ( "" , token . parent . pos , token . parent . end - token . parent . pos + 1 ) ;
160
+ }
161
+ else {
162
+ return createCodeFix ( "" , token . parent . pos - 1 , token . parent . end - token . parent . pos + 1 ) ;
163
+ }
164
+ }
165
+ }
166
+ } ) ;
167
+ }
0 commit comments