// Create a pointer.Config whose scope is the initial packages of lprog // and their dependencies. func setupPTA(prog *ssa.Program, lprog *loader.Program, ptaLog io.Writer, reflection bool) (*pointer.Config, error) { // TODO(adonovan): the body of this function is essentially // duplicated in all go/pointer clients. Refactor. // For each initial package (specified on the command line), // if it has a main function, analyze that, // otherwise analyze its tests, if any. var testPkgs, mains []*ssa.Package for _, info := range lprog.InitialPackages() { initialPkg := prog.Package(info.Pkg) // Add package to the pointer analysis scope. if initialPkg.Func("main") != nil { mains = append(mains, initialPkg) } else { testPkgs = append(testPkgs, initialPkg) } } if testPkgs != nil { if p := prog.CreateTestMainPackage(testPkgs...); p != nil { mains = append(mains, p) } } if mains == nil { return nil, fmt.Errorf("analysis scope has no main and no tests") } return &pointer.Config{ Log: ptaLog, Reflection: reflection, Mains: mains, }, nil }
// FindMains returns the set of all packages loaded into the given // loader.Program which contain main functions func FindMains(p *loader.Program, s *ssa.Program) []*ssa.Package { ips := p.InitialPackages() mains := make([]*ssa.Package, 0, len(ips)) for _, info := range ips { ssaPkg := s.Package(info.Pkg) if ssaPkg.Func("main") != nil { mains = append(mains, ssaPkg) } } return mains }
// ssaValueForExpr returns the ssa.Value of the non-ast.Ident // expression whose path to the root of the AST is path. // func ssaValueForExpr(prog *ssa.Program, qinfo *loader.PackageInfo, path []ast.Node) (value ssa.Value, isAddr bool, err error) { pkg := prog.Package(qinfo.Pkg) pkg.SetDebugMode(true) pkg.Build() fn := ssa.EnclosingFunction(pkg, path) if fn == nil { return nil, false, fmt.Errorf("no SSA function built for this location (dead code?)") } if v, addr := fn.ValueForExpr(path[0].(ast.Expr)); v != nil { return v, addr, nil } return nil, false, fmt.Errorf("can't locate SSA Value for expression in %s", fn) }
// ssaValueForIdent returns the ssa.Value for the ast.Ident whose path // to the root of the AST is path. isAddr reports whether the // ssa.Value is the address denoted by the ast.Ident, not its value. // func ssaValueForIdent(prog *ssa.Program, qinfo *loader.PackageInfo, obj types.Object, path []ast.Node) (value ssa.Value, isAddr bool, err error) { switch obj := obj.(type) { case *types.Var: pkg := prog.Package(qinfo.Pkg) pkg.Build() if v, addr := prog.VarValue(obj, pkg, path); v != nil { return v, addr, nil } return nil, false, fmt.Errorf("can't locate SSA Value for var %s", obj.Name()) case *types.Func: fn := prog.FuncValue(obj) if fn == nil { return nil, false, fmt.Errorf("%s is an interface method", obj) } // TODO(adonovan): there's no point running PTA on a *Func ident. // Eliminate this feature. return fn, false, nil } panic(obj) }
// Create a pointer.Config whose scope is the initial packages of lprog // and their dependencies. func setupPTA(prog *ssa.Program, lprog *loader.Program, ptaLog io.Writer, reflection bool) (*pointer.Config, error) { // For each initial package (specified on the command line), // if it has a main function, analyze that, // otherwise analyze its tests, if any. var mains []*ssa.Package for _, info := range lprog.InitialPackages() { p := prog.Package(info.Pkg) // Add package to the pointer analysis scope. if p.Pkg.Name() == "main" && p.Func("main") != nil { mains = append(mains, p) } else if main := prog.CreateTestMainPackage(p); main != nil { mains = append(mains, main) } } if mains == nil { return nil, fmt.Errorf("analysis scope has no main and no tests") } return &pointer.Config{ Log: ptaLog, Reflection: reflection, Mains: mains, }, nil }
func toSSA(src io.Reader, file, pkg string) (SSA, error) { var fs []Func var conf loader.Config // Parse the file into a ssa file f, _ := conf.ParseFile(file, src) conf.CreateFromFiles("main.go", f) p, _ := conf.Load() buildsanity := content["ssabuild"] == true var ssap *ssa.Program if buildsanity { ssap = ssautil.CreateProgram(p, ssa.SanityCheckFunctions) } else { ssap = ssautil.CreateProgram(p, ssa.NaiveForm) } // Build ssa prog to retrieve all information and the main pkg ssap.Build() mainpkg := ssap.Package(p.InitialPackages()[0].Pkg) for _, m := range mainpkg.Members { if m.Token() == token.FUNC { f, ok := m.(*ssa.Function) if ok { var params []Value for _, p := range f.Params { v := Value{p.Name(), reflect.TypeOf(p).String()} params = append(params, v) } var freevars []Value for _, fv := range f.FreeVars { v := Value{fv.Name(), reflect.TypeOf(fv).String()} freevars = append(freevars, v) } var locals []Value for _, l := range f.Locals { v := Value{l.Name(), reflect.TypeOf(l).String()} locals = append(locals, v) } var blocks []BB for _, b := range f.Blocks { var instrs []Instr for _, i := range b.Instrs { in := Instr{i.String(), reflect.TypeOf(i).String()} instrs = append(instrs, in) } var preds []int for _, p := range b.Preds { preds = append(preds, p.Index) } var succs []int for _, s := range b.Succs { succs = append(succs, s.Index) } bb := BB{b.Index, instrs, preds, succs} blocks = append(blocks, bb) } fn := Func{f.Name(), params, "par_" + f.Name(), freevars, "freevars_" + f.Name(), locals, "locals_" + f.Name(), blocks, "blocks_" + f.Name()} fs = append(fs, fn) } } } return SSA{fs}, nil }
// Returns true if unused func checkObj(expr *ast.Ident, object types.Object, prog *loader.Program, ssaprog *ssa.Program, fset *token.FileSet) (unused bool) { if _, ok := object.(*types.Var); !ok { if debug { fmt.Println("Skipping object", object) } return false } pkg, node, _ := prog.PathEnclosingInterval(expr.Pos(), expr.End()) spkg := ssaprog.Package(pkg.Pkg) f := ssa.EnclosingFunction(spkg, node) if f == nil { if debug { fmt.Printf("Unknown function %v %v %v %v\n", fset.Position(expr.Pos()), object, pkg, prog) } return false } value, _ := f.ValueForExpr(expr) // Unwrap unops and grab the value inside if v, ok := value.(*ssa.UnOp); ok { if debug { fmt.Println("Unwrapping unop") } value = v.X } if debug { fmt.Printf("%v %v: %v %#v\n", fset.Position(expr.Pos()), expr, object, value) } if _, ok := value.(*ssa.Global); ok { if debug { fmt.Printf(" is global\n") } return false } if value == nil { if debug { fmt.Println("Value is nil", object) } return false } refs := value.Referrers() if refs == nil { if debug { fmt.Println("Referrers is nil", object) } return false } if debug { fmt.Printf(" (refs) %v\n", refs) } hasRef := false for _, r := range *refs { _, ok := r.(*ssa.DebugRef) hasRef = hasRef || !ok if debug && !ok { fmt.Printf("%v %v: %v %v\n", fset.Position(expr.Pos()), expr, object, r) } } if !hasRef { unused = true } return unused }