@@ -256,6 +256,48 @@ var NoFloatingPromisesRule = rule.Rule{
256256 return true
257257 }
258258
259+ isFunctionExpression := func (node * ast.Node ) bool {
260+ return ast .IsArrowFunction (node ) || ast .IsFunctionExpression (node )
261+ }
262+
263+ skipOuterExpressions := func (node * ast.Node ) * ast.Node {
264+ return ast .SkipOuterExpressions (node , ast .OEKAll )
265+ }
266+
267+ isAsyncIifeCall := func (node * ast.Node ) bool {
268+ if ! ast .IsCallExpression (node ) {
269+ return false
270+ }
271+ callee := skipOuterExpressions (node .AsCallExpression ().Expression )
272+ return isFunctionExpression (callee ) && ast .IsAsyncFunction (callee )
273+ }
274+
275+ getStaticPropertyName := func (node * ast.Node ) string {
276+ if ! ast .IsPropertyAccessExpression (node ) {
277+ return ""
278+ }
279+ return node .AsPropertyAccessExpression ().Name ().Text ()
280+ }
281+
282+ var containsTypeArgumentCall func (node * ast.Node ) bool
283+ containsTypeArgumentCall = func (node * ast.Node ) bool {
284+ if ast .IsCallExpression (node ) && node .AsCallExpression ().TypeArguments != nil {
285+ return true
286+ }
287+ return node .ForEachChild (func (child * ast.Node ) bool {
288+ return containsTypeArgumentCall (child )
289+ })
290+ }
291+
292+ containsFunctionArgumentWithTypeArgumentCall := func (callExpr * ast.CallExpression ) bool {
293+ for _ , arg := range callExpr .Arguments .Nodes {
294+ if isFunctionExpression (arg ) && containsTypeArgumentCall (arg ) {
295+ return true
296+ }
297+ }
298+ return false
299+ }
300+
259301 var isUnhandledPromise func (
260302 node * ast.Node ,
261303 ) (
@@ -293,6 +335,44 @@ var NoFloatingPromisesRule = rule.Rule{
293335 return isUnhandledPromise (node .Expression ())
294336 }
295337
338+ if ast .IsCallExpression (node ) {
339+ callExpr := node .AsCallExpression ()
340+ callee := skipOuterExpressions (callExpr .Expression )
341+
342+ if isAsyncIifeCall (node ) {
343+ return true , false , false
344+ }
345+
346+ if ast .IsAccessExpression (callee ) && isAsyncIifeCall (callee .Expression ()) {
347+ switch getStaticPropertyName (callee ) {
348+ case "catch" :
349+ if ! isKnownArgumentAt (callExpr .Arguments , 0 ) {
350+ return true , false , false
351+ }
352+ if isFunctionExpression (callExpr .Arguments .Nodes [0 ]) {
353+ return false , false , false
354+ }
355+ return true , true , false
356+ case "then" :
357+ if ! isKnownArgumentAt (callExpr .Arguments , 1 ) {
358+ return true , false , false
359+ }
360+ if isFunctionExpression (callExpr .Arguments .Nodes [1 ]) {
361+ return false , false , false
362+ }
363+ return true , true , false
364+ case "finally" :
365+ return isUnhandledPromise (callee .Expression ())
366+ }
367+ }
368+
369+ // typescript-go can recurse indefinitely when resolving some generic
370+ // calls inside callback return types.
371+ if containsFunctionArgumentWithTypeArgumentCall (callExpr ) {
372+ return false , false , false
373+ }
374+ }
375+
296376 // Check the type. At this point it can't be unhandled if it isn't a promise
297377 // or array thereof.
298378
0 commit comments