@@ -49,21 +49,21 @@ namespace ts.codefix {
4949 registerCodeFix ( {
5050 errorCodes,
5151 getCodeActions ( context ) {
52- const { sourceFile, program, span : { start } , errorCode, cancellationToken, host } = context ;
52+ const { sourceFile, program, span : { start } , errorCode, cancellationToken, host, formatContext , preferences } = context ;
5353
5454 const token = getTokenAtPosition ( sourceFile , start ) ;
5555 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 ) ; } ) ;
5757 const name = declaration && getNameOfDeclaration ( declaration ) ;
5858 return ! name || changes . length === 0 ? undefined
5959 : [ createCodeFixAction ( fixId , changes , [ getDiagnostic ( errorCode , token ) , name . getText ( sourceFile ) ] , fixId , Diagnostics . Infer_all_types_from_usage ) ] ;
6060 } ,
6161 fixIds : [ fixId ] ,
6262 getAllCodeActions ( context ) {
63- const { sourceFile, program, cancellationToken, host } = context ;
63+ const { sourceFile, program, cancellationToken, host, formatContext , preferences } = context ;
6464 const markSeen = nodeSeenTracker ( ) ;
6565 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 ) ;
6767 } ) ;
6868 } ,
6969 } ) ;
@@ -106,7 +106,7 @@ namespace ts.codefix {
106106 return errorCode ;
107107 }
108108
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 {
110110 if ( ! isParameterPropertyModifier ( token . kind ) && token . kind !== SyntaxKind . Identifier && token . kind !== SyntaxKind . DotDotDotToken && token . kind !== SyntaxKind . ThisKeyword ) {
111111 return undefined ;
112112 }
@@ -118,7 +118,7 @@ namespace ts.codefix {
118118 case Diagnostics . Member_0_implicitly_has_an_1_type . code :
119119 case Diagnostics . Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined . code :
120120 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 ) ;
122122 return parent ;
123123 }
124124 if ( isPropertyAccessExpression ( parent ) ) {
@@ -136,7 +136,7 @@ namespace ts.codefix {
136136 case Diagnostics . Variable_0_implicitly_has_an_1_type . code : {
137137 const symbol = program . getTypeChecker ( ) . getSymbolAtLocation ( token ) ;
138138 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 ) ;
140140 return symbol . valueDeclaration ;
141141 }
142142 return undefined ;
@@ -152,14 +152,14 @@ namespace ts.codefix {
152152 // Parameter declarations
153153 case Diagnostics . Parameter_0_implicitly_has_an_1_type . code :
154154 if ( isSetAccessorDeclaration ( containingFunction ) ) {
155- annotateSetAccessor ( changes , sourceFile , containingFunction , program , host , cancellationToken ) ;
155+ annotateSetAccessor ( changes , sourceFile , containingFunction , program , host , cancellationToken , formatContext , preferences ) ;
156156 return containingFunction ;
157157 }
158158 // falls through
159159 case Diagnostics . Rest_parameter_0_implicitly_has_an_any_type . code :
160160 if ( markSeen ( containingFunction ) ) {
161161 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 ) ;
163163 return param ;
164164 }
165165 return undefined ;
@@ -168,15 +168,15 @@ namespace ts.codefix {
168168 case Diagnostics . Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation . code :
169169 case Diagnostics . _0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type . code :
170170 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 ) ;
172172 return containingFunction ;
173173 }
174174 return undefined ;
175175
176176 // Set Accessor declarations
177177 case Diagnostics . Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation . code :
178178 if ( isSetAccessorDeclaration ( containingFunction ) ) {
179- annotateSetAccessor ( changes , sourceFile , containingFunction , program , host , cancellationToken ) ;
179+ annotateSetAccessor ( changes , sourceFile , containingFunction , program , host , cancellationToken , formatContext , preferences ) ;
180180 return containingFunction ;
181181 }
182182 return undefined ;
@@ -194,13 +194,32 @@ namespace ts.codefix {
194194 }
195195 }
196196
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 {
198207 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 ) ;
200209 }
201210 }
202211
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 {
204223 if ( ! isIdentifier ( parameterDeclaration . name ) ) {
205224 return ;
206225 }
@@ -216,7 +235,7 @@ namespace ts.codefix {
216235 if ( needParens ) changes . insertNodeBefore ( sourceFile , first ( containingFunction . parameters ) , createToken ( SyntaxKind . OpenParenToken ) ) ;
217236 for ( const { declaration, type } of parameterInferences ) {
218237 if ( declaration && ! declaration . type && ! declaration . initializer ) {
219- annotate ( changes , sourceFile , declaration , type , program , host ) ;
238+ annotate ( changes , sourceFile , declaration , type , program , host , formatContext , preferences ) ;
220239 }
221240 }
222241 if ( needParens ) changes . insertNodeAfter ( sourceFile , last ( containingFunction . parameters ) , createToken ( SyntaxKind . CloseParenToken ) ) ;
@@ -248,7 +267,16 @@ namespace ts.codefix {
248267 ] ) ;
249268 }
250269
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 {
252280 const param = firstOrUndefined ( setAccessorDeclaration . parameters ) ;
253281 if ( param && isIdentifier ( setAccessorDeclaration . name ) && isIdentifier ( param . name ) ) {
254282 let type = inferTypeForVariableFromUsage ( setAccessorDeclaration . name , program , cancellationToken ) ;
@@ -259,12 +287,12 @@ namespace ts.codefix {
259287 annotateJSDocParameters ( changes , sourceFile , [ { declaration : param , type } ] , program , host ) ;
260288 }
261289 else {
262- annotate ( changes , sourceFile , param , type , program , host ) ;
290+ annotate ( changes , sourceFile , param , type , program , host , formatContext , preferences ) ;
263291 }
264292 }
265293 }
266294
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 {
268296 const typeNode = getTypeNodeIfAccessible ( type , declaration , program , host ) ;
269297 if ( typeNode ) {
270298 if ( isInJSFile ( sourceFile ) && declaration . kind !== SyntaxKind . PropertySignature ) {
@@ -276,12 +304,42 @@ namespace ts.codefix {
276304 const typeTag = isGetAccessorDeclaration ( declaration ) ? createJSDocReturnTag ( typeExpression , "" ) : createJSDocTypeTag ( typeExpression , "" ) ;
277305 addJSDocTags ( changes , sourceFile , parent , [ typeTag ] ) ;
278306 }
279- else {
307+ else if ( ! tryReplaceImportTypeNodeWithAutoImport ( typeNode , changes , sourceFile , declaration , type , program , host , formatContext , preferences ) ) {
280308 changes . tryInsertTypeAnnotation ( sourceFile , declaration , typeNode ) ;
281309 }
282310 }
283311 }
284312
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+
285343 function annotateJSDocParameters ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , parameterInferences : readonly ParameterInference [ ] , program : Program , host : LanguageServiceHost ) : void {
286344 const signature = parameterInferences . length && parameterInferences [ 0 ] . declaration . parent ;
287345 if ( ! signature ) {
0 commit comments