github.com/goplusjs/gopherjs@v1.2.6-0.20211206034512-f187917453b8/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 var list []*types.Var 18 for obj := range v.escaping { 19 list = append(list, obj) 20 } 21 return list 22 } 23 24 type escapeAnalysis struct { 25 info *types.Info 26 escaping map[*types.Var]bool 27 topScope *types.Scope 28 bottomScopes map[*types.Scope]bool 29 } 30 31 func (v *escapeAnalysis) Visit(node ast.Node) (w ast.Visitor) { 32 // huge overapproximation 33 switch n := node.(type) { 34 case *ast.UnaryExpr: 35 if n.Op == token.AND { 36 if _, ok := n.X.(*ast.Ident); ok { 37 return &escapingObjectCollector{v} 38 } 39 } 40 case *ast.FuncLit: 41 v.bottomScopes[v.info.Scopes[n.Type]] = true 42 return &escapingObjectCollector{v} 43 case *ast.ForStmt: 44 v.bottomScopes[v.info.Scopes[n.Body]] = true 45 case *ast.RangeStmt: 46 v.bottomScopes[v.info.Scopes[n.Body]] = true 47 } 48 return v 49 } 50 51 type escapingObjectCollector struct { 52 analysis *escapeAnalysis 53 } 54 55 func (v *escapingObjectCollector) Visit(node ast.Node) (w ast.Visitor) { 56 if id, ok := node.(*ast.Ident); ok { 57 if obj, ok := v.analysis.info.Uses[id].(*types.Var); ok { 58 for s := obj.Parent(); s != nil; s = s.Parent() { 59 if s == v.analysis.topScope { 60 v.analysis.escaping[obj] = true 61 break 62 } 63 if v.analysis.bottomScopes[s] { 64 break 65 } 66 } 67 } 68 } 69 return v 70 }