| // Copyright 2013 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package ssautil // import "golang.org/x/tools/go/ssa/ssautil" |
| |
| import "golang.org/x/tools/go/ssa" |
| |
| // This file defines utilities for visiting the SSA representation of |
| // a Program. |
| // |
| // TODO(adonovan): test coverage. |
| |
| // AllFunctions finds and returns the set of functions potentially |
| // needed by program prog, as determined by a simple linker-style |
| // reachability algorithm starting from the members and method-sets of |
| // each package. The result may include anonymous functions and |
| // synthetic wrappers. |
| // |
| // Precondition: all packages are built. |
| // |
| func AllFunctions(prog *ssa.Program) map[*ssa.Function]bool { |
| visit := visitor{ |
| prog: prog, |
| seen: make(map[*ssa.Function]bool), |
| } |
| visit.program() |
| return visit.seen |
| } |
| |
| type visitor struct { |
| prog *ssa.Program |
| seen map[*ssa.Function]bool |
| } |
| |
| func (visit *visitor) program() { |
| for _, pkg := range visit.prog.AllPackages() { |
| for _, mem := range pkg.Members { |
| if fn, ok := mem.(*ssa.Function); ok { |
| visit.function(fn) |
| } |
| } |
| } |
| for _, T := range visit.prog.RuntimeTypes() { |
| mset := visit.prog.MethodSets.MethodSet(T) |
| for i, n := 0, mset.Len(); i < n; i++ { |
| visit.function(visit.prog.MethodValue(mset.At(i))) |
| } |
| } |
| } |
| |
| func (visit *visitor) function(fn *ssa.Function) { |
| if !visit.seen[fn] { |
| visit.seen[fn] = true |
| var buf [10]*ssa.Value // avoid alloc in common case |
| for _, b := range fn.Blocks { |
| for _, instr := range b.Instrs { |
| for _, op := range instr.Operands(buf[:0]) { |
| if fn, ok := (*op).(*ssa.Function); ok { |
| visit.function(fn) |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| // MainPackages returns the subset of the specified packages |
| // named "main" that define a main function. |
| // The result may include synthetic "testmain" packages. |
| func MainPackages(pkgs []*ssa.Package) []*ssa.Package { |
| var mains []*ssa.Package |
| for _, pkg := range pkgs { |
| if pkg.Pkg.Name() == "main" && pkg.Func("main") != nil { |
| mains = append(mains, pkg) |
| } |
| } |
| return mains |
| } |