Beispiel #1
0
// 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
}
Beispiel #2
0
// 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
}
Beispiel #3
0
// 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)
}
Beispiel #4
0
// 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)
}
Beispiel #5
0
// 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
}
Beispiel #6
0
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
}
Beispiel #7
0
// 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
}