@@ -11,14 +11,15 @@ namespace ts.codefix {
1111 Diagnostics . Property_0_is_missing_in_type_1_but_required_in_type_2 . code ,
1212 Diagnostics . Type_0_is_missing_the_following_properties_from_type_1_Colon_2 . code ,
1313 Diagnostics . Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more . code ,
14+ Diagnostics . Argument_of_type_0_is_not_assignable_to_parameter_of_type_1 . code ,
1415 Diagnostics . Cannot_find_name_0 . code
1516 ] ;
1617
1718 registerCodeFix ( {
1819 errorCodes,
1920 getCodeActions ( context ) {
2021 const typeChecker = context . program . getTypeChecker ( ) ;
21- const info = getInfo ( context . sourceFile , context . span . start , typeChecker , context . program ) ;
22+ const info = getInfo ( context . sourceFile , context . span . start , context . errorCode , typeChecker , context . program ) ;
2223 if ( ! info ) {
2324 return undefined ;
2425 }
@@ -49,7 +50,7 @@ namespace ts.codefix {
4950
5051 return createCombinedCodeActions ( textChanges . ChangeTracker . with ( context , changes => {
5152 eachDiagnostic ( context , errorCodes , diag => {
52- const info = getInfo ( diag . file , diag . start , checker , context . program ) ;
53+ const info = getInfo ( diag . file , diag . start , diag . code , checker , context . program ) ;
5354 if ( ! info || ! addToSeen ( seen , getNodeId ( info . parentDeclaration ) + "#" + info . token . text ) ) {
5455 return ;
5556 }
@@ -139,6 +140,7 @@ namespace ts.codefix {
139140 readonly token : Identifier ;
140141 readonly properties : Symbol [ ] ;
141142 readonly parentDeclaration : ObjectLiteralExpression ;
143+ readonly indentation ?: number ;
142144 }
143145
144146 interface JsxAttributesInfo {
@@ -148,43 +150,53 @@ namespace ts.codefix {
148150 readonly parentDeclaration : JsxOpeningLikeElement ;
149151 }
150152
151- function getInfo ( sourceFile : SourceFile , tokenPos : number , checker : TypeChecker , program : Program ) : Info | undefined {
153+ function getInfo ( sourceFile : SourceFile , tokenPos : number , errorCode : number , checker : TypeChecker , program : Program ) : Info | undefined {
152154 // The identifier of the missing property. eg:
153155 // this.missing = 1;
154156 // ^^^^^^^
155157 const token = getTokenAtPosition ( sourceFile , tokenPos ) ;
156- if ( ! isIdentifier ( token ) && ! isPrivateIdentifier ( token ) ) {
157- return undefined ;
158+ const parent = token . parent ;
159+
160+ if ( errorCode === Diagnostics . Argument_of_type_0_is_not_assignable_to_parameter_of_type_1 . code ) {
161+ if ( ! ( token . kind === SyntaxKind . OpenBraceToken && isObjectLiteralExpression ( parent ) && isCallExpression ( parent . parent ) ) ) return undefined ;
162+
163+ const argIndex = findIndex ( parent . parent . arguments , arg => arg === parent ) ;
164+ if ( argIndex < 0 ) return undefined ;
165+
166+ const signature = singleOrUndefined ( checker . getSignaturesOfType ( checker . getTypeAtLocation ( parent . parent . expression ) , SignatureKind . Call ) ) ;
167+ if ( ! ( signature && signature . declaration && signature . parameters [ argIndex ] ) ) return undefined ;
168+
169+ const param = signature . parameters [ argIndex ] . valueDeclaration ;
170+ if ( ! ( param && isParameter ( param ) && isIdentifier ( param . name ) ) ) return undefined ;
171+
172+ const properties = arrayFrom ( checker . getUnmatchedProperties ( checker . getTypeAtLocation ( parent ) , checker . getTypeAtLocation ( param ) , /* requireOptionalProperties */ false , /* matchDiscriminantProperties */ false ) ) ;
173+ if ( ! length ( properties ) ) return undefined ;
174+ return { kind : InfoKind . ObjectLiteral , token : param . name , properties, indentation : 0 , parentDeclaration : parent } ;
158175 }
159176
160- const { parent } = token ;
177+ if ( ! isMemberName ( token ) ) return undefined ;
178+
161179 if ( isIdentifier ( token ) && hasInitializer ( parent ) && parent . initializer && isObjectLiteralExpression ( parent . initializer ) ) {
162180 const properties = arrayFrom ( checker . getUnmatchedProperties ( checker . getTypeAtLocation ( parent . initializer ) , checker . getTypeAtLocation ( token ) , /* requireOptionalProperties */ false , /* matchDiscriminantProperties */ false ) ) ;
163- if ( length ( properties ) ) {
164- return { kind : InfoKind . ObjectLiteral , token, properties, parentDeclaration : parent . initializer } ;
165- }
181+ if ( ! length ( properties ) ) return undefined ;
182+ return { kind : InfoKind . ObjectLiteral , token, properties, indentation : undefined , parentDeclaration : parent . initializer } ;
166183 }
167184
168185 if ( isIdentifier ( token ) && isJsxOpeningLikeElement ( token . parent ) ) {
169186 const attributes = getUnmatchedAttributes ( checker , token . parent ) ;
170- if ( length ( attributes ) ) {
171- return { kind : InfoKind . JsxAttributes , token, attributes, parentDeclaration : token . parent } ;
172- }
187+ if ( ! length ( attributes ) ) return undefined ;
188+ return { kind : InfoKind . JsxAttributes , token, attributes, parentDeclaration : token . parent } ;
173189 }
174190
175191 if ( isIdentifier ( token ) && isCallExpression ( parent ) ) {
176192 return { kind : InfoKind . Function , token, call : parent , sourceFile, modifierFlags : ModifierFlags . None , parentDeclaration : sourceFile } ;
177193 }
178194
179- if ( ! isPropertyAccessExpression ( parent ) ) {
180- return undefined ;
181- }
195+ if ( ! isPropertyAccessExpression ( parent ) ) return undefined ;
182196
183197 const leftExpressionType = skipConstraint ( checker . getTypeAtLocation ( parent . expression ) ) ;
184- const { symbol } = leftExpressionType ;
185- if ( ! symbol || ! symbol . declarations ) {
186- return undefined ;
187- }
198+ const symbol = leftExpressionType . symbol ;
199+ if ( ! symbol || ! symbol . declarations ) return undefined ;
188200
189201 if ( isIdentifier ( token ) && isCallExpression ( parent . parent ) ) {
190202 const moduleDeclaration = find ( symbol . declarations , isModuleDeclaration ) ;
@@ -194,9 +206,7 @@ namespace ts.codefix {
194206 }
195207
196208 const moduleSourceFile = find ( symbol . declarations , isSourceFile ) ;
197- if ( sourceFile . commonJsModuleIndicator ) {
198- return ;
199- }
209+ if ( sourceFile . commonJsModuleIndicator ) return undefined ;
200210
201211 if ( moduleSourceFile && ! isSourceFileFromLibrary ( program , moduleSourceFile ) ) {
202212 return { kind : InfoKind . Function , token, call : parent . parent , sourceFile : moduleSourceFile , modifierFlags : ModifierFlags . Export , parentDeclaration : moduleSourceFile } ;
@@ -205,17 +215,13 @@ namespace ts.codefix {
205215
206216 const classDeclaration = find ( symbol . declarations , isClassLike ) ;
207217 // Don't suggest adding private identifiers to anything other than a class.
208- if ( ! classDeclaration && isPrivateIdentifier ( token ) ) {
209- return undefined ;
210- }
218+ if ( ! classDeclaration && isPrivateIdentifier ( token ) ) return undefined ;
211219
212220 // Prefer to change the class instead of the interface if they are merged
213221 const classOrInterface = classDeclaration || find ( symbol . declarations , isInterfaceDeclaration ) ;
214222 if ( classOrInterface && ! isSourceFileFromLibrary ( program , classOrInterface . getSourceFile ( ) ) ) {
215223 const makeStatic = ( ( leftExpressionType as TypeReference ) . target || leftExpressionType ) !== checker . getDeclaredTypeOfSymbol ( symbol ) ;
216- if ( makeStatic && ( isPrivateIdentifier ( token ) || isInterfaceDeclaration ( classOrInterface ) ) ) {
217- return undefined ;
218- }
224+ if ( makeStatic && ( isPrivateIdentifier ( token ) || isInterfaceDeclaration ( classOrInterface ) ) ) return undefined ;
219225
220226 const declSourceFile = classOrInterface . getSourceFile ( ) ;
221227 const modifierFlags = ( makeStatic ? ModifierFlags . Static : 0 ) | ( startsWithUnderscore ( token . text ) ? ModifierFlags . Private : 0 ) ;
@@ -475,7 +481,12 @@ namespace ts.codefix {
475481 const initializer = prop . valueDeclaration ? tryGetValueFromType ( context , checker , importAdder , quotePreference , checker . getTypeAtLocation ( prop . valueDeclaration ) ) : createUndefined ( ) ;
476482 return factory . createPropertyAssignment ( prop . name , initializer ) ;
477483 } ) ;
478- changes . replaceNode ( context . sourceFile , info . parentDeclaration , factory . createObjectLiteralExpression ( [ ...info . parentDeclaration . properties , ...props ] , /*multiLine*/ true ) ) ;
484+ const options = {
485+ leadingTriviaOption : textChanges . LeadingTriviaOption . Exclude ,
486+ trailingTriviaOption : textChanges . TrailingTriviaOption . Exclude ,
487+ indentation : info . indentation
488+ } ;
489+ changes . replaceNode ( context . sourceFile , info . parentDeclaration , factory . createObjectLiteralExpression ( [ ...info . parentDeclaration . properties , ...props ] , /*multiLine*/ true ) , options ) ;
479490 }
480491
481492 function tryGetValueFromType ( context : CodeFixContextBase , checker : TypeChecker , importAdder : ImportAdder , quotePreference : QuotePreference , type : Type ) : Expression {
0 commit comments