.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.1.1 / go / ir / irutil / util.go
1 package irutil
2
3 import (
4         "go/types"
5         "strings"
6
7         "honnef.co/go/tools/go/ir"
8         "honnef.co/go/tools/go/types/typeutil"
9 )
10
11 func Reachable(from, to *ir.BasicBlock) bool {
12         if from == to {
13                 return true
14         }
15         if from.Dominates(to) {
16                 return true
17         }
18
19         found := false
20         Walk(from, func(b *ir.BasicBlock) bool {
21                 if b == to {
22                         found = true
23                         return false
24                 }
25                 return true
26         })
27         return found
28 }
29
30 func Walk(b *ir.BasicBlock, fn func(*ir.BasicBlock) bool) {
31         seen := map[*ir.BasicBlock]bool{}
32         wl := []*ir.BasicBlock{b}
33         for len(wl) > 0 {
34                 b := wl[len(wl)-1]
35                 wl = wl[:len(wl)-1]
36                 if seen[b] {
37                         continue
38                 }
39                 seen[b] = true
40                 if !fn(b) {
41                         continue
42                 }
43                 wl = append(wl, b.Succs...)
44         }
45 }
46
47 func Vararg(x *ir.Slice) ([]ir.Value, bool) {
48         var out []ir.Value
49         slice, ok := x.X.(*ir.Alloc)
50         if !ok {
51                 return nil, false
52         }
53         for _, ref := range *slice.Referrers() {
54                 if ref == x {
55                         continue
56                 }
57                 if ref.Block() != x.Block() {
58                         return nil, false
59                 }
60                 idx, ok := ref.(*ir.IndexAddr)
61                 if !ok {
62                         return nil, false
63                 }
64                 if len(*idx.Referrers()) != 1 {
65                         return nil, false
66                 }
67                 store, ok := (*idx.Referrers())[0].(*ir.Store)
68                 if !ok {
69                         return nil, false
70                 }
71                 out = append(out, store.Val)
72         }
73         return out, true
74 }
75
76 func CallName(call *ir.CallCommon) string {
77         if call.IsInvoke() {
78                 return ""
79         }
80         switch v := call.Value.(type) {
81         case *ir.Function:
82                 fn, ok := v.Object().(*types.Func)
83                 if !ok {
84                         return ""
85                 }
86                 return typeutil.FuncName(fn)
87         case *ir.Builtin:
88                 return v.Name()
89         }
90         return ""
91 }
92
93 func IsCallTo(call *ir.CallCommon, name string) bool { return CallName(call) == name }
94
95 func IsCallToAny(call *ir.CallCommon, names ...string) bool {
96         q := CallName(call)
97         for _, name := range names {
98                 if q == name {
99                         return true
100                 }
101         }
102         return false
103 }
104
105 func FilterDebug(instr []ir.Instruction) []ir.Instruction {
106         var out []ir.Instruction
107         for _, ins := range instr {
108                 if _, ok := ins.(*ir.DebugRef); !ok {
109                         out = append(out, ins)
110                 }
111         }
112         return out
113 }
114
115 func IsExample(fn *ir.Function) bool {
116         if !strings.HasPrefix(fn.Name(), "Example") {
117                 return false
118         }
119         f := fn.Prog.Fset.File(fn.Pos())
120         if f == nil {
121                 return false
122         }
123         return strings.HasSuffix(f.Name(), "_test.go")
124 }
125
126 // Flatten recursively returns the underlying value of an ir.Sigma or
127 // ir.Phi node. If all edges in an ir.Phi node are the same (after
128 // flattening), the flattened edge will get returned. If flattening is
129 // not possible, nil is returned.
130 func Flatten(v ir.Value) ir.Value {
131         failed := false
132         seen := map[ir.Value]struct{}{}
133         var out ir.Value
134         var dfs func(v ir.Value)
135         dfs = func(v ir.Value) {
136                 if failed {
137                         return
138                 }
139                 if _, ok := seen[v]; ok {
140                         return
141                 }
142                 seen[v] = struct{}{}
143
144                 switch v := v.(type) {
145                 case *ir.Sigma:
146                         dfs(v.X)
147                 case *ir.Phi:
148                         for _, e := range v.Edges {
149                                 dfs(e)
150                         }
151                 default:
152                         if out == nil {
153                                 out = v
154                         } else if out != v {
155                                 failed = true
156                         }
157                 }
158         }
159         dfs(v)
160
161         if failed {
162                 return nil
163         }
164         return out
165 }