1
2
3
4
5 package ssa
6
7
8
9 import (
10 "fmt"
11 "go/types"
12
13 "golang.org/x/tools/go/types/typeutil"
14 "golang.org/x/tools/internal/aliases"
15 )
16
17
18
19
20
21
22
23
24
25
26 func (prog *Program) MethodValue(sel *types.Selection) *Function {
27 if sel.Kind() != types.MethodVal {
28 panic(fmt.Sprintf("MethodValue(%s) kind != MethodVal", sel))
29 }
30 T := sel.Recv()
31 if types.IsInterface(T) {
32 return nil
33 }
34
35 if prog.isParameterized(T) {
36 return nil
37 }
38
39 if prog.mode&LogSource != 0 {
40 defer logStack("MethodValue %s %v", T, sel)()
41 }
42
43 var cr creator
44
45 m := func() *Function {
46 prog.methodsMu.Lock()
47 defer prog.methodsMu.Unlock()
48
49
50 mset, ok := prog.methodSets.At(T).(*methodSet)
51 if !ok {
52 mset = &methodSet{mapping: make(map[string]*Function)}
53 prog.methodSets.Set(T, mset)
54 }
55
56
57 id := sel.Obj().Id()
58 fn, ok := mset.mapping[id]
59 if !ok {
60 obj := sel.Obj().(*types.Func)
61 needsPromotion := len(sel.Index()) > 1
62 needsIndirection := !isPointer(recvType(obj)) && isPointer(T)
63 if needsPromotion || needsIndirection {
64 fn = createWrapper(prog, toSelection(sel), &cr)
65 } else {
66 fn = prog.objectMethod(obj, &cr)
67 }
68 if fn.Signature.Recv() == nil {
69 panic(fn)
70 }
71 mset.mapping[id] = fn
72 }
73
74 return fn
75 }()
76
77 b := builder{created: &cr}
78 b.iterate()
79
80 return m
81 }
82
83
84
85
86
87
88
89
90
91 func (prog *Program) objectMethod(obj *types.Func, cr *creator) *Function {
92 sig := obj.Type().(*types.Signature)
93 if sig.Recv() == nil {
94 panic("not a method: " + obj.String())
95 }
96
97
98 if fn := prog.FuncValue(obj); fn != nil {
99 return fn
100 }
101
102
103 if originObj := obj.Origin(); originObj != obj {
104 origin := prog.objectMethod(originObj, cr)
105 assert(origin.typeparams.Len() > 0, "origin is not generic")
106 targs := receiverTypeArgs(obj)
107 return origin.instance(targs, cr)
108 }
109
110
111 prog.objectMethodsMu.Lock()
112 defer prog.objectMethodsMu.Unlock()
113 fn, ok := prog.objectMethods[obj]
114 if !ok {
115 fn = createFunction(prog, obj, obj.Name(), nil, nil, "", cr)
116 fn.Synthetic = "from type information (on demand)"
117
118 if prog.objectMethods == nil {
119 prog.objectMethods = make(map[*types.Func]*Function)
120 }
121 prog.objectMethods[obj] = fn
122 }
123 return fn
124 }
125
126
127
128
129 func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function {
130 sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name)
131 if sel == nil {
132 panic(fmt.Sprintf("%s has no method %s", T, types.Id(pkg, name)))
133 }
134 return prog.MethodValue(sel)
135 }
136
137
138 type methodSet struct {
139 mapping map[string]*Function
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 func (prog *Program) RuntimeTypes() []types.Type {
156 prog.runtimeTypesMu.Lock()
157 defer prog.runtimeTypesMu.Unlock()
158 return prog.runtimeTypes.Keys()
159 }
160
161
162
163
164
165
166
167
168 func forEachReachable(msets *typeutil.MethodSetCache, T types.Type, f func(types.Type) bool) {
169 var visit func(T types.Type, skip bool)
170 visit = func(T types.Type, skip bool) {
171 if !skip {
172 if !f(T) {
173 return
174 }
175 }
176
177
178 tmset := msets.MethodSet(T)
179 for i := 0; i < tmset.Len(); i++ {
180 sig := tmset.At(i).Type().(*types.Signature)
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205 visit(sig.Params(), true)
206 visit(sig.Results(), true)
207 }
208
209 switch T := T.(type) {
210 case *aliases.Alias:
211 visit(aliases.Unalias(T), skip)
212
213 case *types.Basic:
214
215
216 case *types.Interface:
217
218
219 case *types.Pointer:
220 visit(T.Elem(), false)
221
222 case *types.Slice:
223 visit(T.Elem(), false)
224
225 case *types.Chan:
226 visit(T.Elem(), false)
227
228 case *types.Map:
229 visit(T.Key(), false)
230 visit(T.Elem(), false)
231
232 case *types.Signature:
233 if T.Recv() != nil {
234 panic(fmt.Sprintf("Signature %s has Recv %s", T, T.Recv()))
235 }
236 visit(T.Params(), true)
237 visit(T.Results(), true)
238
239 case *types.Named:
240
241
242 visit(types.NewPointer(T), false)
243
244
245
246
247
248 visit(T.Underlying(), true)
249
250 case *types.Array:
251 visit(T.Elem(), false)
252
253 case *types.Struct:
254 for i, n := 0, T.NumFields(); i < n; i++ {
255
256
257 visit(T.Field(i).Type(), false)
258 }
259
260 case *types.Tuple:
261 for i, n := 0, T.Len(); i < n; i++ {
262 visit(T.At(i).Type(), false)
263 }
264
265 case *types.TypeParam, *types.Union:
266
267 panic(T)
268
269 default:
270 panic(T)
271 }
272 }
273 visit(T, false)
274 }
275
View as plain text