@@ -3,6 +3,7 @@ namespace ts {
3
3
export function computeSuggestionDiagnostics ( sourceFile : SourceFile , program : Program , cancellationToken : CancellationToken ) : DiagnosticWithLocation [ ] {
4
4
program . getSemanticDiagnostics ( sourceFile , cancellationToken ) ;
5
5
const diags : DiagnosticWithLocation [ ] = [ ] ;
6
+ const checker = program . getDiagnosticsProducingTypeChecker ( ) ;
6
7
7
8
if ( sourceFile . commonJsModuleIndicator &&
8
9
( programContainsEs6Modules ( program ) || compilerOptionsIndicateEs6Modules ( program . getCompilerOptions ( ) ) ) &&
@@ -68,6 +69,9 @@ namespace ts {
68
69
}
69
70
}
70
71
72
+ if ( isFunctionLikeDeclaration ( node ) ) {
73
+ addConvertToAsyncFunctionDiagnostics ( node , checker , diags ) ;
74
+ }
71
75
node . forEachChild ( check ) ;
72
76
}
73
77
}
@@ -109,7 +113,64 @@ namespace ts {
109
113
}
110
114
}
111
115
116
+ function addConvertToAsyncFunctionDiagnostics ( node : FunctionLikeDeclaration , checker : TypeChecker , diags : DiagnosticWithLocation [ ] ) : void {
117
+
118
+ const functionType = node . type ? checker . getTypeFromTypeNode ( node . type ) : undefined ;
119
+ if ( isAsyncFunction ( node ) || ! node . body || ! functionType ) {
120
+ return ;
121
+ }
122
+
123
+ const callSignatures = checker . getSignaturesOfType ( functionType , SignatureKind . Call ) ;
124
+ const returnType = callSignatures . length ? checker . getReturnTypeOfSignature ( callSignatures [ 0 ] ) : undefined ;
125
+
126
+ if ( ! returnType || ! checker . getPromisedTypeOfPromise ( returnType ) ) {
127
+ return ;
128
+ }
129
+
130
+ // collect all the return statements
131
+ // check that a property access expression exists in there and that it is a handler
132
+ const returnStatements = getReturnStatementsWithPromiseHandlers ( node ) ;
133
+ if ( returnStatements . length > 0 ) {
134
+ diags . push ( createDiagnosticForNode ( isVariableDeclaration ( node . parent ) ? node . parent . name : node , Diagnostics . This_may_be_converted_to_an_async_function ) ) ;
135
+ }
136
+ }
137
+
112
138
function getErrorNodeFromCommonJsIndicator ( commonJsModuleIndicator : Node ) : Node {
113
139
return isBinaryExpression ( commonJsModuleIndicator ) ? commonJsModuleIndicator . left : commonJsModuleIndicator ;
114
140
}
141
+
142
+ /** @internal */
143
+ export function getReturnStatementsWithPromiseHandlers ( node : Node ) : Node [ ] {
144
+ const returnStatements : Node [ ] = [ ] ;
145
+ if ( isFunctionLike ( node ) ) {
146
+ forEachChild ( node , visit ) ;
147
+ }
148
+ else {
149
+ visit ( node ) ;
150
+ }
151
+
152
+ function visit ( child : Node ) {
153
+ if ( isFunctionLike ( child ) ) {
154
+ return ;
155
+ }
156
+
157
+ if ( isReturnStatement ( child ) ) {
158
+ forEachChild ( child , addHandlers ) ;
159
+ }
160
+
161
+ function addHandlers ( returnChild : Node ) {
162
+ if ( isPromiseHandler ( returnChild ) ) {
163
+ returnStatements . push ( child as ReturnStatement ) ;
164
+ }
165
+ }
166
+
167
+ forEachChild ( child , visit ) ;
168
+ }
169
+ return returnStatements ;
170
+ }
171
+
172
+ function isPromiseHandler ( node : Node ) : boolean {
173
+ return ( isCallExpression ( node ) && isPropertyAccessExpression ( node . expression ) &&
174
+ ( node . expression . name . text === "then" || node . expression . name . text === "catch" ) ) ;
175
+ }
115
176
}
0 commit comments