.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.1.1 / go / ir / irutil / terminates.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.1.1/go/ir/irutil/terminates.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.1.1/go/ir/irutil/terminates.go
new file mode 100644 (file)
index 0000000..84e7503
--- /dev/null
@@ -0,0 +1,70 @@
+package irutil
+
+import (
+       "go/types"
+
+       "honnef.co/go/tools/go/ir"
+)
+
+// Terminates reports whether fn is supposed to return, that is if it
+// has at least one theoretic path that returns from the function.
+// Explicit panics do not count as terminating.
+func Terminates(fn *ir.Function) bool {
+       if fn.Blocks == nil {
+               // assuming that a function terminates is the conservative
+               // choice
+               return true
+       }
+
+       for _, block := range fn.Blocks {
+               if _, ok := block.Control().(*ir.Return); ok {
+                       if len(block.Preds) == 0 {
+                               return true
+                       }
+                       for _, pred := range block.Preds {
+                               switch ctrl := pred.Control().(type) {
+                               case *ir.Panic:
+                                       // explicit panics do not count as terminating
+                               case *ir.If:
+                                       // Check if we got here by receiving from a closed
+                                       // time.Tick channel – this cannot happen at
+                                       // runtime and thus doesn't constitute termination
+                                       iff := ctrl
+                                       if !ok {
+                                               return true
+                                       }
+                                       ex, ok := iff.Cond.(*ir.Extract)
+                                       if !ok {
+                                               return true
+                                       }
+                                       if ex.Index != 1 {
+                                               return true
+                                       }
+                                       recv, ok := ex.Tuple.(*ir.Recv)
+                                       if !ok {
+                                               return true
+                                       }
+                                       call, ok := recv.Chan.(*ir.Call)
+                                       if !ok {
+                                               return true
+                                       }
+                                       fn, ok := call.Common().Value.(*ir.Function)
+                                       if !ok {
+                                               return true
+                                       }
+                                       fn2, ok := fn.Object().(*types.Func)
+                                       if !ok {
+                                               return true
+                                       }
+                                       if fn2.FullName() != "time.Tick" {
+                                               return true
+                                       }
+                               default:
+                                       // we've reached the exit block
+                                       return true
+                               }
+                       }
+               }
+       }
+       return false
+}