@@ -15,6 +15,15 @@ namespace ts.codefix {
15
15
Diagnostics . Cannot_find_name_0 . code
16
16
] ;
17
17
18
+ enum InfoKind {
19
+ TypeLikeDeclaration ,
20
+ Enum ,
21
+ Function ,
22
+ ObjectLiteral ,
23
+ JsxAttributes ,
24
+ Signature ,
25
+ }
26
+
18
27
registerCodeFix ( {
19
28
errorCodes,
20
29
getCodeActions ( context ) {
@@ -31,7 +40,7 @@ namespace ts.codefix {
31
40
const changes = textChanges . ChangeTracker . with ( context , t => addJsxAttributes ( t , context , info ) ) ;
32
41
return [ createCodeFixAction ( fixMissingAttributes , changes , Diagnostics . Add_missing_attributes , fixMissingAttributes , Diagnostics . Add_all_missing_attributes ) ] ;
33
42
}
34
- if ( info . kind === InfoKind . Function ) {
43
+ if ( info . kind === InfoKind . Function || info . kind === InfoKind . Signature ) {
35
44
const changes = textChanges . ChangeTracker . with ( context , t => addFunctionDeclaration ( t , context , info ) ) ;
36
45
return [ createCodeFixAction ( fixMissingFunctionDeclaration , changes , [ Diagnostics . Add_missing_function_declaration_0 , info . token . text ] , fixMissingFunctionDeclaration , Diagnostics . Add_all_missing_function_declarations ) ] ;
37
46
}
@@ -54,8 +63,7 @@ namespace ts.codefix {
54
63
if ( ! info || ! addToSeen ( seen , getNodeId ( info . parentDeclaration ) + "#" + info . token . text ) ) {
55
64
return ;
56
65
}
57
-
58
- if ( fixId === fixMissingFunctionDeclaration && info . kind === InfoKind . Function ) {
66
+ if ( fixId === fixMissingFunctionDeclaration && ( info . kind === InfoKind . Function || info . kind === InfoKind . Signature ) ) {
59
67
addFunctionDeclaration ( changes , context , info ) ;
60
68
}
61
69
else if ( fixId === fixMissingProperties && info . kind === InfoKind . ObjectLiteral ) {
@@ -107,8 +115,7 @@ namespace ts.codefix {
107
115
} ,
108
116
} ) ;
109
117
110
- const enum InfoKind { TypeLikeDeclaration , Enum , Function , ObjectLiteral , JsxAttributes }
111
- type Info = TypeLikeDeclarationInfo | EnumInfo | FunctionInfo | ObjectLiteralInfo | JsxAttributesInfo ;
118
+ type Info = TypeLikeDeclarationInfo | EnumInfo | FunctionInfo | ObjectLiteralInfo | JsxAttributesInfo | SignatureInfo ;
112
119
113
120
interface EnumInfo {
114
121
readonly kind : InfoKind . Enum ;
@@ -132,7 +139,7 @@ namespace ts.codefix {
132
139
readonly token : Identifier ;
133
140
readonly sourceFile : SourceFile ;
134
141
readonly modifierFlags : ModifierFlags ;
135
- readonly parentDeclaration : SourceFile | ModuleDeclaration ;
142
+ readonly parentDeclaration : SourceFile | ModuleDeclaration | ReturnStatement ;
136
143
}
137
144
138
145
interface ObjectLiteralInfo {
@@ -150,6 +157,14 @@ namespace ts.codefix {
150
157
readonly parentDeclaration : JsxOpeningLikeElement ;
151
158
}
152
159
160
+ interface SignatureInfo {
161
+ readonly kind : InfoKind . Signature ;
162
+ readonly token : Identifier ;
163
+ readonly signature : Signature ;
164
+ readonly sourceFile : SourceFile ;
165
+ readonly parentDeclaration : Node ;
166
+ }
167
+
153
168
function getInfo ( sourceFile : SourceFile , tokenPos : number , errorCode : number , checker : TypeChecker , program : Program ) : Info | undefined {
154
169
// The identifier of the missing property. eg:
155
170
// this.missing = 1;
@@ -190,8 +205,16 @@ namespace ts.codefix {
190
205
return { kind : InfoKind . JsxAttributes , token, attributes, parentDeclaration : token . parent } ;
191
206
}
192
207
193
- if ( isIdentifier ( token ) && isCallExpression ( parent ) && parent . expression === token ) {
194
- return { kind : InfoKind . Function , token, call : parent , sourceFile, modifierFlags : ModifierFlags . None , parentDeclaration : sourceFile } ;
208
+ if ( isIdentifier ( token ) ) {
209
+ const type = checker . getContextualType ( token ) ;
210
+ if ( type && getObjectFlags ( type ) & ObjectFlags . Anonymous ) {
211
+ const signature = firstOrUndefined ( checker . getSignaturesOfType ( type , SignatureKind . Call ) ) ;
212
+ if ( signature === undefined ) return undefined ;
213
+ return { kind : InfoKind . Signature , token, signature, sourceFile, parentDeclaration : findScope ( token ) } ;
214
+ }
215
+ if ( isCallExpression ( parent ) && parent . expression === token ) {
216
+ return { kind : InfoKind . Function , token, call : parent , sourceFile, modifierFlags : ModifierFlags . None , parentDeclaration : findScope ( token ) } ;
217
+ }
195
218
}
196
219
197
220
if ( ! isPropertyAccessExpression ( parent ) ) return undefined ;
@@ -451,10 +474,19 @@ namespace ts.codefix {
451
474
} ) ;
452
475
}
453
476
454
- function addFunctionDeclaration ( changes : textChanges . ChangeTracker , context : CodeFixContextBase , info : FunctionInfo ) {
477
+ function addFunctionDeclaration ( changes : textChanges . ChangeTracker , context : CodeFixContextBase , info : FunctionInfo | SignatureInfo ) {
478
+ const quotePreference = getQuotePreference ( context . sourceFile , context . preferences ) ;
455
479
const importAdder = createImportAdder ( context . sourceFile , context . program , context . preferences , context . host ) ;
456
- const functionDeclaration = createSignatureDeclarationFromCallExpression ( SyntaxKind . FunctionDeclaration , context , importAdder , info . call , idText ( info . token ) , info . modifierFlags , info . parentDeclaration ) as FunctionDeclaration ;
457
- changes . insertNodeAtEndOfScope ( info . sourceFile , info . parentDeclaration , functionDeclaration ) ;
480
+ const functionDeclaration = info . kind === InfoKind . Function
481
+ ? createSignatureDeclarationFromCallExpression ( SyntaxKind . FunctionDeclaration , context , importAdder , info . call , idText ( info . token ) , info . modifierFlags , info . parentDeclaration )
482
+ : createSignatureDeclarationFromSignature ( SyntaxKind . FunctionDeclaration , context , quotePreference , info . signature , createStubbedBody ( Diagnostics . Function_not_implemented . message , quotePreference ) , info . token , /*modifiers*/ undefined , /*optional*/ undefined , /*enclosingDeclaration*/ undefined , importAdder ) ;
483
+ if ( functionDeclaration === undefined ) {
484
+ Debug . fail ( "fixMissingFunctionDeclaration codefix got unexpected error." ) ;
485
+ }
486
+
487
+ isReturnStatement ( info . parentDeclaration )
488
+ ? changes . insertNodeBefore ( info . sourceFile , info . parentDeclaration , functionDeclaration , /*blankLineBetween*/ true )
489
+ : changes . insertNodeAtEndOfScope ( info . sourceFile , info . parentDeclaration , functionDeclaration ) ;
458
490
importAdder . writeFixes ( changes ) ;
459
491
}
460
492
@@ -618,4 +650,12 @@ namespace ts.codefix {
618
650
}
619
651
return createPropertyNameNodeForIdentifierOrLiteral ( symbol . name , target , quotePreference === QuotePreference . Single ) ;
620
652
}
653
+
654
+ function findScope ( node : Node ) {
655
+ if ( findAncestor ( node , isJsxExpression ) ) {
656
+ const returnStatement = findAncestor ( node . parent , isReturnStatement ) ;
657
+ if ( returnStatement ) return returnStatement ;
658
+ }
659
+ return getSourceFileOfNode ( node ) ;
660
+ }
621
661
}
0 commit comments