1
2
3
4
5
6
7
8
9 package free
10
11 import (
12 "go/ast"
13 "go/token"
14 )
15
16
17
18
19
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 func Names(n ast.Node, includeComplitIdents bool) map[string]bool {
45 v := &freeVisitor{
46 free: make(map[string]bool),
47 includeComplitIdents: includeComplitIdents,
48 }
49
50
51
52
53 v.openScope()
54 ast.Walk(v, n)
55 v.closeScope()
56 if v.scope != nil {
57 panic("unbalanced scopes")
58 }
59 return v.free
60 }
61
62
63 type freeVisitor struct {
64 scope *scope
65 free map[string]bool
66 includeComplitIdents bool
67 }
68
69
70
71 type scope struct {
72 names map[string]bool
73 outer *scope
74 }
75
76 func (s *scope) defined(name string) bool {
77 for ; s != nil; s = s.outer {
78 if s.names[name] {
79 return true
80 }
81 }
82 return false
83 }
84
85 func (v *freeVisitor) Visit(n ast.Node) ast.Visitor {
86 switch n := n.(type) {
87
88
89 case *ast.Ident:
90 v.use(n)
91
92 case *ast.FuncLit:
93 v.openScope()
94 defer v.closeScope()
95 v.walkFuncType(nil, n.Type)
96 v.walkBody(n.Body)
97
98 case *ast.SelectorExpr:
99 v.walk(n.X)
100
101
102 case *ast.StructType:
103 v.openScope()
104 defer v.closeScope()
105 v.walkFieldList(n.Fields)
106
107 case *ast.FuncType:
108 v.openScope()
109 defer v.closeScope()
110 v.walkFuncType(nil, n)
111
112 case *ast.CompositeLit:
113 v.walk(n.Type)
114 for _, e := range n.Elts {
115 if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
116 if ident, _ := kv.Key.(*ast.Ident); ident != nil {
117
118
119
120
121 if v.includeComplitIdents {
122
123
124 v.use(ident)
125 } else {
126
127 }
128 } else {
129 v.walk(kv.Key)
130 }
131 v.walk(kv.Value)
132 } else {
133 v.walk(e)
134 }
135 }
136
137 case *ast.InterfaceType:
138 v.openScope()
139 defer v.closeScope()
140 v.walkFieldList(n.Methods)
141
142
143 case *ast.AssignStmt:
144 walkSlice(v, n.Rhs)
145 if n.Tok == token.DEFINE {
146 v.shortVarDecl(n.Lhs)
147 } else {
148 walkSlice(v, n.Lhs)
149 }
150
151 case *ast.LabeledStmt:
152
153 v.walk(n.Stmt)
154
155 case *ast.BranchStmt:
156
157
158 case *ast.BlockStmt:
159 v.openScope()
160 defer v.closeScope()
161 walkSlice(v, n.List)
162
163 case *ast.IfStmt:
164 v.openScope()
165 defer v.closeScope()
166 v.walk(n.Init)
167 v.walk(n.Cond)
168 v.walk(n.Body)
169 v.walk(n.Else)
170
171 case *ast.CaseClause:
172 walkSlice(v, n.List)
173 v.openScope()
174 defer v.closeScope()
175 walkSlice(v, n.Body)
176
177 case *ast.SwitchStmt:
178 v.openScope()
179 defer v.closeScope()
180 v.walk(n.Init)
181 v.walk(n.Tag)
182 v.walkBody(n.Body)
183
184 case *ast.TypeSwitchStmt:
185 v.openScope()
186 defer v.closeScope()
187 if n.Init != nil {
188 v.walk(n.Init)
189 }
190 v.walk(n.Assign)
191
192 v.walkBody(n.Body)
193
194 case *ast.CommClause:
195 v.openScope()
196 defer v.closeScope()
197 v.walk(n.Comm)
198 walkSlice(v, n.Body)
199
200 case *ast.SelectStmt:
201 v.walkBody(n.Body)
202
203 case *ast.ForStmt:
204 v.openScope()
205 defer v.closeScope()
206 v.walk(n.Init)
207 v.walk(n.Cond)
208 v.walk(n.Post)
209 v.walk(n.Body)
210
211 case *ast.RangeStmt:
212 v.openScope()
213 defer v.closeScope()
214 v.walk(n.X)
215 var lhs []ast.Expr
216 if n.Key != nil {
217 lhs = append(lhs, n.Key)
218 }
219 if n.Value != nil {
220 lhs = append(lhs, n.Value)
221 }
222 if len(lhs) > 0 {
223 if n.Tok == token.DEFINE {
224 v.shortVarDecl(lhs)
225 } else {
226 walkSlice(v, lhs)
227 }
228 }
229 v.walk(n.Body)
230
231
232 case *ast.GenDecl:
233 switch n.Tok {
234 case token.CONST, token.VAR:
235 for _, spec := range n.Specs {
236 spec := spec.(*ast.ValueSpec)
237 walkSlice(v, spec.Values)
238 v.walk(spec.Type)
239 v.declare(spec.Names...)
240 }
241
242 case token.TYPE:
243 for _, spec := range n.Specs {
244 spec := spec.(*ast.TypeSpec)
245
246
247
248 v.declare(spec.Name)
249 if spec.TypeParams != nil {
250 v.openScope()
251 defer v.closeScope()
252 v.walkTypeParams(spec.TypeParams)
253 }
254 v.walk(spec.Type)
255 }
256
257 case token.IMPORT:
258 panic("encountered import declaration in free analysis")
259 }
260
261 case *ast.FuncDecl:
262 if n.Recv == nil && n.Name.Name != "init" {
263 v.declare(n.Name)
264 }
265 v.openScope()
266 defer v.closeScope()
267 v.walkTypeParams(n.Type.TypeParams)
268 v.walkFuncType(n.Recv, n.Type)
269 v.walkBody(n.Body)
270
271 default:
272 return v
273 }
274
275 return nil
276 }
277
278 func (v *freeVisitor) openScope() {
279 v.scope = &scope{map[string]bool{}, v.scope}
280 }
281
282 func (v *freeVisitor) closeScope() {
283 v.scope = v.scope.outer
284 }
285
286 func (v *freeVisitor) walk(n ast.Node) {
287 if n != nil {
288 ast.Walk(v, n)
289 }
290 }
291
292 func (v *freeVisitor) walkFuncType(recv *ast.FieldList, typ *ast.FuncType) {
293
294 v.walkRecvFieldType(recv)
295 v.walkFieldTypes(typ.Params)
296 v.walkFieldTypes(typ.Results)
297
298
299 v.declareFieldNames(recv)
300 v.declareFieldNames(typ.Params)
301 v.declareFieldNames(typ.Results)
302 }
303
304
305
306 func (v *freeVisitor) walkRecvFieldType(list *ast.FieldList) {
307 if list == nil {
308 return
309 }
310 for _, f := range list.List {
311 typ := f.Type
312 if ptr, ok := typ.(*ast.StarExpr); ok {
313 typ = ptr.X
314 }
315
316
317 var (
318 base ast.Expr
319 indices []ast.Expr
320 )
321 switch typ := typ.(type) {
322 case *ast.IndexExpr:
323 base, indices = typ.X, []ast.Expr{typ.Index}
324 case *ast.IndexListExpr:
325 base, indices = typ.X, typ.Indices
326 default:
327 base = typ
328 }
329 for _, expr := range indices {
330 if id, ok := expr.(*ast.Ident); ok {
331 v.declare(id)
332 }
333 }
334 v.walk(base)
335 }
336 }
337
338
339
340
341 func (v *freeVisitor) walkTypeParams(list *ast.FieldList) {
342 v.declareFieldNames(list)
343 v.walkFieldTypes(list)
344 }
345
346 func (v *freeVisitor) walkBody(body *ast.BlockStmt) {
347 if body == nil {
348 return
349 }
350 walkSlice(v, body.List)
351 }
352
353 func (v *freeVisitor) walkFieldList(list *ast.FieldList) {
354 if list == nil {
355 return
356 }
357 v.walkFieldTypes(list)
358 v.declareFieldNames(list)
359 }
360
361 func (v *freeVisitor) shortVarDecl(lhs []ast.Expr) {
362
363
364
365
366
367
368 for _, x := range lhs {
369
370
371 if id, ok := x.(*ast.Ident); ok {
372 v.declare(id)
373 }
374 }
375 }
376
377 func walkSlice[S ~[]E, E ast.Node](r *freeVisitor, list S) {
378 for _, e := range list {
379 r.walk(e)
380 }
381 }
382
383
384
385 func (v *freeVisitor) walkFieldTypes(list *ast.FieldList) {
386 if list != nil {
387 for _, f := range list.List {
388 v.walk(f.Type)
389 }
390 }
391 }
392
393
394
395
396 func (v *freeVisitor) declareFieldNames(list *ast.FieldList) {
397 if list != nil {
398 for _, f := range list.List {
399 v.declare(f.Names...)
400 }
401 }
402 }
403
404
405 func (v *freeVisitor) use(ident *ast.Ident) {
406 if s := ident.Name; s != "_" && !v.scope.defined(s) {
407 v.free[s] = true
408 }
409 }
410
411
412 func (v *freeVisitor) declare(idents ...*ast.Ident) {
413 for _, id := range idents {
414 if id.Name != "_" {
415 v.scope.names[id.Name] = true
416 }
417 }
418 }
419
View as plain text