1
2
3
4
5 package inline
6
7
8
9 import (
10 "go/ast"
11 "go/token"
12 "go/types"
13
14 "golang.org/x/tools/internal/typesinternal"
15 )
16
17 const (
18 rinf = -1
19 winf = -2
20 )
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 func calleefx(info *types.Info, body *ast.BlockStmt, paramInfos map[*types.Var]*paramInfo) []int {
48
49
50
51
52
53
54
55
56 var effects []int
57 seen := make(map[int]bool)
58 effect := func(i int) {
59 if !seen[i] {
60 seen[i] = true
61 effects = append(effects, i)
62 }
63 }
64
65
66 unknown := func() {
67 effect(winf)
68
69
70
71
72
73
74
75
76
77 for _, pinfo := range paramInfos {
78 if !pinfo.IsResult && len(pinfo.Refs) > 0 {
79 effect(pinfo.Index)
80 }
81 }
82 }
83
84 var visitExpr func(n ast.Expr)
85 var visitStmt func(n ast.Stmt) bool
86 visitExpr = func(n ast.Expr) {
87 switch n := n.(type) {
88 case *ast.Ident:
89 if v, ok := info.Uses[n].(*types.Var); ok && !v.IsField() {
90
91 if v.Parent() == v.Pkg().Scope() {
92 effect(rinf)
93 }
94
95
96 if pinfo, ok := paramInfos[v]; ok && !pinfo.IsResult {
97 effect(pinfo.Index)
98 }
99
100
101 }
102
103 case *ast.BasicLit:
104
105
106 case *ast.FuncLit:
107
108
109
110
111
112 case *ast.CompositeLit:
113 for _, elt := range n.Elts {
114 visitExpr(elt)
115 }
116
117 case *ast.ParenExpr:
118 visitExpr(n.X)
119
120 case *ast.SelectorExpr:
121 if seln, ok := info.Selections[n]; ok {
122 visitExpr(n.X)
123
124
125 switch seln.Kind() {
126 case types.MethodExpr:
127
128
129
130
131 case types.MethodVal, types.FieldVal:
132
133
134
135 if indirectSelection(seln) {
136 effect(rinf)
137 }
138 }
139 } else {
140
141 visitExpr(n.Sel)
142 }
143
144 case *ast.IndexExpr:
145 if tv := info.Types[n.Index]; tv.IsType() {
146
147 } else {
148 visitExpr(n.X)
149 visitExpr(n.Index)
150 switch tv.Type.Underlying().(type) {
151 case *types.Slice, *types.Pointer:
152 effect(rinf)
153 }
154 }
155
156 case *ast.IndexListExpr:
157
158
159 case *ast.SliceExpr:
160 visitExpr(n.X)
161 visitExpr(n.Low)
162 visitExpr(n.High)
163 visitExpr(n.Max)
164
165 case *ast.TypeAssertExpr:
166 visitExpr(n.X)
167
168 case *ast.CallExpr:
169 if info.Types[n.Fun].IsType() {
170
171 visitExpr(n.Args[0])
172 } else {
173
174 visitExpr(n.Fun)
175 for i, arg := range n.Args {
176 if i == 0 && info.Types[arg].IsType() {
177 continue
178 }
179 visitExpr(arg)
180 }
181
182
183
184
185 if !typesinternal.CallsPureBuiltin(info, n) {
186 unknown()
187 }
188 }
189
190 case *ast.StarExpr:
191 visitExpr(n.X)
192 effect(rinf)
193
194 case *ast.UnaryExpr:
195 visitExpr(n.X)
196 if n.Op == token.ARROW {
197 unknown()
198 }
199
200 case *ast.BinaryExpr:
201 visitExpr(n.X)
202 visitExpr(n.Y)
203
204 case *ast.KeyValueExpr:
205 visitExpr(n.Key)
206 visitExpr(n.Value)
207
208 case *ast.BadExpr:
209
210
211 case nil:
212
213
214 default:
215
216 panic(n)
217 }
218 }
219
220
221
222
223
224
225
226
227
228 visitStmt = func(n ast.Stmt) bool {
229 switch n := n.(type) {
230 case *ast.DeclStmt:
231 decl := n.Decl.(*ast.GenDecl)
232 for _, spec := range decl.Specs {
233 switch spec := spec.(type) {
234 case *ast.ValueSpec:
235 for _, v := range spec.Values {
236 visitExpr(v)
237 }
238
239 case *ast.TypeSpec:
240
241 }
242 }
243
244 case *ast.LabeledStmt:
245 return visitStmt(n.Stmt)
246
247 case *ast.ExprStmt:
248 visitExpr(n.X)
249
250 case *ast.SendStmt:
251 visitExpr(n.Chan)
252 visitExpr(n.Value)
253 unknown()
254
255 case *ast.IncDecStmt:
256 visitExpr(n.X)
257 unknown()
258
259 case *ast.AssignStmt:
260 for _, lhs := range n.Lhs {
261 visitExpr(lhs)
262 }
263 for _, rhs := range n.Rhs {
264 visitExpr(rhs)
265 }
266 for _, lhs := range n.Lhs {
267 id, _ := lhs.(*ast.Ident)
268 if id != nil && id.Name == "_" {
269 continue
270 }
271 if n.Tok == token.DEFINE && id != nil && info.Defs[id] != nil {
272 continue
273 }
274 unknown()
275 break
276 }
277
278 case *ast.GoStmt:
279 visitExpr(n.Call.Fun)
280 for _, arg := range n.Call.Args {
281 visitExpr(arg)
282 }
283 unknown()
284
285 case *ast.DeferStmt:
286 visitExpr(n.Call.Fun)
287 for _, arg := range n.Call.Args {
288 visitExpr(arg)
289 }
290 unknown()
291
292 case *ast.ReturnStmt:
293 for _, res := range n.Results {
294 visitExpr(res)
295 }
296 return false
297
298 case *ast.BlockStmt:
299 for _, stmt := range n.List {
300 if !visitStmt(stmt) {
301 return false
302 }
303 }
304
305 case *ast.BranchStmt:
306 unknown()
307
308 case *ast.IfStmt:
309 visitStmt(n.Init)
310 visitExpr(n.Cond)
311 unknown()
312
313 case *ast.SwitchStmt:
314 visitStmt(n.Init)
315 visitExpr(n.Tag)
316 unknown()
317
318 case *ast.TypeSwitchStmt:
319 visitStmt(n.Init)
320 visitStmt(n.Assign)
321 unknown()
322
323 case *ast.SelectStmt:
324 unknown()
325
326 case *ast.ForStmt:
327 visitStmt(n.Init)
328 visitExpr(n.Cond)
329 unknown()
330
331 case *ast.RangeStmt:
332 visitExpr(n.X)
333 unknown()
334
335 case *ast.EmptyStmt, *ast.BadStmt:
336
337
338 case nil:
339
340
341 default:
342 panic(n)
343 }
344 return true
345 }
346 visitStmt(body)
347
348 return effects
349 }
350
View as plain text