@@ -49,21 +49,21 @@ namespace ts.codefix {
49
49
registerCodeFix ( {
50
50
errorCodes,
51
51
getCodeActions ( context ) {
52
- const { sourceFile, program, span : { start } , errorCode, cancellationToken, host } = context ;
52
+ const { sourceFile, program, span : { start } , errorCode, cancellationToken, host, formatContext , preferences } = context ;
53
53
54
54
const token = getTokenAtPosition ( sourceFile , start ) ;
55
55
let declaration ! : Declaration | undefined ;
56
- const changes = textChanges . ChangeTracker . with ( context , changes => { declaration = doChange ( changes , sourceFile , token , errorCode , program , cancellationToken , /*markSeen*/ returnTrue , host ) ; } ) ;
56
+ const changes = textChanges . ChangeTracker . with ( context , changes => { declaration = doChange ( changes , sourceFile , token , errorCode , program , cancellationToken , /*markSeen*/ returnTrue , host , formatContext , preferences ) ; } ) ;
57
57
const name = declaration && getNameOfDeclaration ( declaration ) ;
58
58
return ! name || changes . length === 0 ? undefined
59
59
: [ createCodeFixAction ( fixId , changes , [ getDiagnostic ( errorCode , token ) , name . getText ( sourceFile ) ] , fixId , Diagnostics . Infer_all_types_from_usage ) ] ;
60
60
} ,
61
61
fixIds : [ fixId ] ,
62
62
getAllCodeActions ( context ) {
63
- const { sourceFile, program, cancellationToken, host } = context ;
63
+ const { sourceFile, program, cancellationToken, host, formatContext , preferences } = context ;
64
64
const markSeen = nodeSeenTracker ( ) ;
65
65
return codeFixAll ( context , errorCodes , ( changes , err ) => {
66
- doChange ( changes , sourceFile , getTokenAtPosition ( err . file , err . start ) , err . code , program , cancellationToken , markSeen , host ) ;
66
+ doChange ( changes , sourceFile , getTokenAtPosition ( err . file , err . start ) , err . code , program , cancellationToken , markSeen , host , formatContext , preferences ) ;
67
67
} ) ;
68
68
} ,
69
69
} ) ;
@@ -106,7 +106,7 @@ namespace ts.codefix {
106
106
return errorCode ;
107
107
}
108
108
109
- function doChange ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , token : Node , errorCode : number , program : Program , cancellationToken : CancellationToken , markSeen : NodeSeenTracker , host : LanguageServiceHost ) : Declaration | undefined {
109
+ function doChange ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , token : Node , errorCode : number , program : Program , cancellationToken : CancellationToken , markSeen : NodeSeenTracker , host : LanguageServiceHost , formatContext : formatting . FormatContext , preferences : UserPreferences ) : Declaration | undefined {
110
110
if ( ! isParameterPropertyModifier ( token . kind ) && token . kind !== SyntaxKind . Identifier && token . kind !== SyntaxKind . DotDotDotToken && token . kind !== SyntaxKind . ThisKeyword ) {
111
111
return undefined ;
112
112
}
@@ -118,7 +118,7 @@ namespace ts.codefix {
118
118
case Diagnostics . Member_0_implicitly_has_an_1_type . code :
119
119
case Diagnostics . Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined . code :
120
120
if ( ( isVariableDeclaration ( parent ) && markSeen ( parent ) ) || isPropertyDeclaration ( parent ) || isPropertySignature ( parent ) ) { // handle bad location
121
- annotateVariableDeclaration ( changes , sourceFile , parent , program , host , cancellationToken ) ;
121
+ annotateVariableDeclaration ( changes , sourceFile , parent , program , host , cancellationToken , formatContext , preferences ) ;
122
122
return parent ;
123
123
}
124
124
if ( isPropertyAccessExpression ( parent ) ) {
@@ -136,7 +136,7 @@ namespace ts.codefix {
136
136
case Diagnostics . Variable_0_implicitly_has_an_1_type . code : {
137
137
const symbol = program . getTypeChecker ( ) . getSymbolAtLocation ( token ) ;
138
138
if ( symbol && symbol . valueDeclaration && isVariableDeclaration ( symbol . valueDeclaration ) && markSeen ( symbol . valueDeclaration ) ) {
139
- annotateVariableDeclaration ( changes , sourceFile , symbol . valueDeclaration , program , host , cancellationToken ) ;
139
+ annotateVariableDeclaration ( changes , sourceFile , symbol . valueDeclaration , program , host , cancellationToken , formatContext , preferences ) ;
140
140
return symbol . valueDeclaration ;
141
141
}
142
142
return undefined ;
@@ -152,14 +152,14 @@ namespace ts.codefix {
152
152
// Parameter declarations
153
153
case Diagnostics . Parameter_0_implicitly_has_an_1_type . code :
154
154
if ( isSetAccessorDeclaration ( containingFunction ) ) {
155
- annotateSetAccessor ( changes , sourceFile , containingFunction , program , host , cancellationToken ) ;
155
+ annotateSetAccessor ( changes , sourceFile , containingFunction , program , host , cancellationToken , formatContext , preferences ) ;
156
156
return containingFunction ;
157
157
}
158
158
// falls through
159
159
case Diagnostics . Rest_parameter_0_implicitly_has_an_any_type . code :
160
160
if ( markSeen ( containingFunction ) ) {
161
161
const param = cast ( parent , isParameter ) ;
162
- annotateParameters ( changes , sourceFile , param , containingFunction , program , host , cancellationToken ) ;
162
+ annotateParameters ( changes , sourceFile , param , containingFunction , program , host , cancellationToken , formatContext , preferences ) ;
163
163
return param ;
164
164
}
165
165
return undefined ;
@@ -168,15 +168,15 @@ namespace ts.codefix {
168
168
case Diagnostics . Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation . code :
169
169
case Diagnostics . _0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type . code :
170
170
if ( isGetAccessorDeclaration ( containingFunction ) && isIdentifier ( containingFunction . name ) ) {
171
- annotate ( changes , sourceFile , containingFunction , inferTypeForVariableFromUsage ( containingFunction . name , program , cancellationToken ) , program , host ) ;
171
+ annotate ( changes , sourceFile , containingFunction , inferTypeForVariableFromUsage ( containingFunction . name , program , cancellationToken ) , program , host , formatContext , preferences ) ;
172
172
return containingFunction ;
173
173
}
174
174
return undefined ;
175
175
176
176
// Set Accessor declarations
177
177
case Diagnostics . Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation . code :
178
178
if ( isSetAccessorDeclaration ( containingFunction ) ) {
179
- annotateSetAccessor ( changes , sourceFile , containingFunction , program , host , cancellationToken ) ;
179
+ annotateSetAccessor ( changes , sourceFile , containingFunction , program , host , cancellationToken , formatContext , preferences ) ;
180
180
return containingFunction ;
181
181
}
182
182
return undefined ;
@@ -194,13 +194,32 @@ namespace ts.codefix {
194
194
}
195
195
}
196
196
197
- function annotateVariableDeclaration ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , declaration : VariableDeclaration | PropertyDeclaration | PropertySignature , program : Program , host : LanguageServiceHost , cancellationToken : CancellationToken ) : void {
197
+ function annotateVariableDeclaration (
198
+ changes : textChanges . ChangeTracker ,
199
+ sourceFile : SourceFile ,
200
+ declaration : VariableDeclaration | PropertyDeclaration | PropertySignature ,
201
+ program : Program ,
202
+ host : LanguageServiceHost ,
203
+ cancellationToken : CancellationToken ,
204
+ formatContext : formatting . FormatContext ,
205
+ preferences : UserPreferences ,
206
+ ) : void {
198
207
if ( isIdentifier ( declaration . name ) ) {
199
- annotate ( changes , sourceFile , declaration , inferTypeForVariableFromUsage ( declaration . name , program , cancellationToken ) , program , host ) ;
208
+ annotate ( changes , sourceFile , declaration , inferTypeForVariableFromUsage ( declaration . name , program , cancellationToken ) , program , host , formatContext , preferences ) ;
200
209
}
201
210
}
202
211
203
- function annotateParameters ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , parameterDeclaration : ParameterDeclaration , containingFunction : FunctionLike , program : Program , host : LanguageServiceHost , cancellationToken : CancellationToken ) : void {
212
+ function annotateParameters (
213
+ changes : textChanges . ChangeTracker ,
214
+ sourceFile : SourceFile ,
215
+ parameterDeclaration : ParameterDeclaration ,
216
+ containingFunction : FunctionLike ,
217
+ program : Program ,
218
+ host : LanguageServiceHost ,
219
+ cancellationToken : CancellationToken ,
220
+ formatContext : formatting . FormatContext ,
221
+ preferences : UserPreferences ,
222
+ ) : void {
204
223
if ( ! isIdentifier ( parameterDeclaration . name ) ) {
205
224
return ;
206
225
}
@@ -216,7 +235,7 @@ namespace ts.codefix {
216
235
if ( needParens ) changes . insertNodeBefore ( sourceFile , first ( containingFunction . parameters ) , createToken ( SyntaxKind . OpenParenToken ) ) ;
217
236
for ( const { declaration, type } of parameterInferences ) {
218
237
if ( declaration && ! declaration . type && ! declaration . initializer ) {
219
- annotate ( changes , sourceFile , declaration , type , program , host ) ;
238
+ annotate ( changes , sourceFile , declaration , type , program , host , formatContext , preferences ) ;
220
239
}
221
240
}
222
241
if ( needParens ) changes . insertNodeAfter ( sourceFile , last ( containingFunction . parameters ) , createToken ( SyntaxKind . CloseParenToken ) ) ;
@@ -248,7 +267,16 @@ namespace ts.codefix {
248
267
] ) ;
249
268
}
250
269
251
- function annotateSetAccessor ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , setAccessorDeclaration : SetAccessorDeclaration , program : Program , host : LanguageServiceHost , cancellationToken : CancellationToken ) : void {
270
+ function annotateSetAccessor (
271
+ changes : textChanges . ChangeTracker ,
272
+ sourceFile : SourceFile ,
273
+ setAccessorDeclaration : SetAccessorDeclaration ,
274
+ program : Program ,
275
+ host : LanguageServiceHost ,
276
+ cancellationToken : CancellationToken ,
277
+ formatContext : formatting . FormatContext ,
278
+ preferences : UserPreferences ,
279
+ ) : void {
252
280
const param = firstOrUndefined ( setAccessorDeclaration . parameters ) ;
253
281
if ( param && isIdentifier ( setAccessorDeclaration . name ) && isIdentifier ( param . name ) ) {
254
282
let type = inferTypeForVariableFromUsage ( setAccessorDeclaration . name , program , cancellationToken ) ;
@@ -259,12 +287,12 @@ namespace ts.codefix {
259
287
annotateJSDocParameters ( changes , sourceFile , [ { declaration : param , type } ] , program , host ) ;
260
288
}
261
289
else {
262
- annotate ( changes , sourceFile , param , type , program , host ) ;
290
+ annotate ( changes , sourceFile , param , type , program , host , formatContext , preferences ) ;
263
291
}
264
292
}
265
293
}
266
294
267
- function annotate ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , declaration : textChanges . TypeAnnotatable , type : Type , program : Program , host : LanguageServiceHost ) : void {
295
+ function annotate ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , declaration : textChanges . TypeAnnotatable , type : Type , program : Program , host : LanguageServiceHost , formatContext : formatting . FormatContext , preferences : UserPreferences ) : void {
268
296
const typeNode = getTypeNodeIfAccessible ( type , declaration , program , host ) ;
269
297
if ( typeNode ) {
270
298
if ( isInJSFile ( sourceFile ) && declaration . kind !== SyntaxKind . PropertySignature ) {
@@ -276,12 +304,42 @@ namespace ts.codefix {
276
304
const typeTag = isGetAccessorDeclaration ( declaration ) ? createJSDocReturnTag ( typeExpression , "" ) : createJSDocTypeTag ( typeExpression , "" ) ;
277
305
addJSDocTags ( changes , sourceFile , parent , [ typeTag ] ) ;
278
306
}
279
- else {
307
+ else if ( ! tryReplaceImportTypeNodeWithAutoImport ( typeNode , changes , sourceFile , declaration , type , program , host , formatContext , preferences ) ) {
280
308
changes . tryInsertTypeAnnotation ( sourceFile , declaration , typeNode ) ;
281
309
}
282
310
}
283
311
}
284
312
313
+ function tryReplaceImportTypeNodeWithAutoImport ( typeNode : TypeNode , changes : textChanges . ChangeTracker , sourceFile : SourceFile , declaration : textChanges . TypeAnnotatable , type : Type , program : Program , host : LanguageServiceHost , formatContext : formatting . FormatContext , preferences : UserPreferences ) : boolean {
314
+ if ( isLiteralImportTypeNode ( typeNode ) && typeNode . qualifier && type . symbol ) {
315
+ // Replace 'import("./a").SomeType' with 'SomeType' and an actual import if possible
316
+ const moduleSymbol = find ( type . symbol . declarations , d => ! ! d . getSourceFile ( ) . externalModuleIndicator ) ?. getSourceFile ( ) . symbol ;
317
+ // Symbol for the left-most thing after the dot
318
+ if ( moduleSymbol ) {
319
+ const symbol = getFirstIdentifier ( typeNode . qualifier ) . symbol ;
320
+ const action = getImportCompletionAction (
321
+ symbol ,
322
+ moduleSymbol ,
323
+ sourceFile ,
324
+ symbol . name ,
325
+ host ,
326
+ program ,
327
+ formatContext ,
328
+ declaration . pos ,
329
+ preferences ,
330
+ ) ;
331
+ if ( action . codeAction . changes . length && changes . tryInsertTypeAnnotation ( sourceFile , declaration , createTypeReferenceNode ( typeNode . qualifier , typeNode . typeArguments ) ) ) {
332
+ for ( const change of action . codeAction . changes ) {
333
+ const file = sourceFile . fileName === change . fileName ? sourceFile : Debug . assertDefined ( program . getSourceFile ( change . fileName ) ) ;
334
+ changes . pushRaw ( file , change ) ;
335
+ }
336
+ return true ;
337
+ }
338
+ }
339
+ }
340
+ return false ;
341
+ }
342
+
285
343
function annotateJSDocParameters ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , parameterInferences : readonly ParameterInference [ ] , program : Program , host : LanguageServiceHost ) : void {
286
344
const signature = parameterInferences . length && parameterInferences [ 0 ] . declaration . parent ;
287
345
if ( ! signature ) {
0 commit comments