Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / functions / terminates.go
1 package functions
2
3 import (
4         "go/types"
5
6         "honnef.co/go/tools/ir"
7 )
8
9 // Terminates reports whether fn is supposed to return, that is if it
10 // has at least one theoretic path that returns from the function.
11 // Explicit panics do not count as terminating.
12 func Terminates(fn *ir.Function) bool {
13         if fn.Blocks == nil {
14                 // assuming that a function terminates is the conservative
15                 // choice
16                 return true
17         }
18
19         for _, block := range fn.Blocks {
20                 if _, ok := block.Control().(*ir.Return); ok {
21                         if len(block.Preds) == 0 {
22                                 return true
23                         }
24                         for _, pred := range block.Preds {
25                                 switch ctrl := pred.Control().(type) {
26                                 case *ir.Panic:
27                                         // explicit panics do not count as terminating
28                                 case *ir.If:
29                                         // Check if we got here by receiving from a closed
30                                         // time.Tick channel – this cannot happen at
31                                         // runtime and thus doesn't constitute termination
32                                         iff := ctrl
33                                         if !ok {
34                                                 return true
35                                         }
36                                         ex, ok := iff.Cond.(*ir.Extract)
37                                         if !ok {
38                                                 return true
39                                         }
40                                         if ex.Index != 1 {
41                                                 return true
42                                         }
43                                         recv, ok := ex.Tuple.(*ir.Recv)
44                                         if !ok {
45                                                 return true
46                                         }
47                                         call, ok := recv.Chan.(*ir.Call)
48                                         if !ok {
49                                                 return true
50                                         }
51                                         fn, ok := call.Common().Value.(*ir.Function)
52                                         if !ok {
53                                                 return true
54                                         }
55                                         fn2, ok := fn.Object().(*types.Func)
56                                         if !ok {
57                                                 return true
58                                         }
59                                         if fn2.FullName() != "time.Tick" {
60                                                 return true
61                                         }
62                                 default:
63                                         // we've reached the exit block
64                                         return true
65                                 }
66                         }
67                 }
68         }
69         return false
70 }