github.com/gopherjs/gopherjs@v1.19.0-beta1.0.20240506212314-27071a8796e4/compiler/analysis/escape.go (about) 1 package analysis 2 3 import ( 4 "go/ast" 5 "go/token" 6 "go/types" 7 ) 8 9 func EscapingObjects(n ast.Node, info *types.Info) []*types.Var { 10 v := escapeAnalysis{ 11 info: info, 12 escaping: make(map[*types.Var]bool), 13 topScope: info.Scopes[n], 14 bottomScopes: make(map[*types.Scope]bool), 15 } 16 ast.Walk(&v, n) 17 return v.ordered 18 } 19 20 type escapeAnalysis struct { 21 info *types.Info 22 escaping map[*types.Var]bool 23 ordered []*types.Var 24 topScope *types.Scope 25 bottomScopes map[*types.Scope]bool 26 } 27 28 func (v *escapeAnalysis) Visit(node ast.Node) (w ast.Visitor) { 29 // huge overapproximation 30 switch n := node.(type) { 31 case *ast.UnaryExpr: 32 if n.Op == token.AND { 33 if _, ok := n.X.(*ast.Ident); ok { 34 return &escapingObjectCollector{v} 35 } 36 } 37 case *ast.FuncLit: 38 v.bottomScopes[v.info.Scopes[n.Type]] = true 39 return &escapingObjectCollector{v} 40 case *ast.ForStmt: 41 v.bottomScopes[v.info.Scopes[n.Body]] = true 42 case *ast.RangeStmt: 43 v.bottomScopes[v.info.Scopes[n.Body]] = true 44 } 45 return v 46 } 47 48 type escapingObjectCollector struct { 49 analysis *escapeAnalysis 50 } 51 52 func (v *escapingObjectCollector) Visit(node ast.Node) (w ast.Visitor) { 53 if id, ok := node.(*ast.Ident); ok { 54 if obj, ok := v.analysis.info.Uses[id].(*types.Var); ok { 55 for s := obj.Parent(); s != nil; s = s.Parent() { 56 if s == v.analysis.topScope { 57 if !v.analysis.escaping[obj] { 58 v.analysis.escaping[obj] = true 59 v.analysis.ordered = append(v.analysis.ordered, obj) 60 } 61 break 62 } 63 if v.analysis.bottomScopes[s] { 64 break 65 } 66 } 67 } 68 } 69 return v 70 }