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  }