예제 #1
0
파일: call.go 프로젝트: nickng/dingo-hunter
func findMethod(prog *ssa.Program, meth *types.Func, typ types.Type, infer *TypeInfer) *ssa.Function {
	if meth != nil {
		return prog.LookupMethod(typ, meth.Pkg(), meth.Name())
	}
	infer.Logger.Fatal(ErrMethodNotFound)
	return nil
}
예제 #2
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
}
예제 #3
0
// mainPackage returns the main package to analyze.
// The resulting package has a main() function.
func mainPackage(prog *ssa.Program, tests bool) (*ssa.Package, error) {
	pkgs := prog.AllPackages()

	// TODO(adonovan): allow independent control over tests, mains and libraries.
	// TODO(adonovan): put this logic in a library; we keep reinventing it.

	if tests {
		// If -test, use all packages' tests.
		if len(pkgs) > 0 {
			if main := prog.CreateTestMainPackage(pkgs...); main != nil {
				return main, nil
			}
		}
		return nil, fmt.Errorf("no tests")
	}

	// Otherwise, use the first package named main.
	for _, pkg := range pkgs {
		if pkg.Object.Name() == "main" {
			if pkg.Func("main") == nil {
				return nil, fmt.Errorf("no func main() in main package")
			}
			return pkg, nil
		}
	}

	return nil, fmt.Errorf("no main package")
}
예제 #4
0
파일: main.go 프로젝트: elliott5/shouldexp
func getFuncs(prog *ssa.Program, pkg *ssa.Package) []*ssa.Function {
	funcs := make([]*ssa.Function, 0, len(pkg.Members))
	for _, mem := range pkg.Members {
		fn, ok := mem.(*ssa.Function)
		if ok {
			if iu := unicode.IsUpper(rune(fn.Name()[0])); iu || *nonExp {
				funcs = append(funcs, fn)
			}
		}
		typ, ok := mem.(*ssa.Type)
		if ok {
			mset := prog.MethodSets.MethodSet(typ.Type())
			for i, n := 0, mset.Len(); i < n; i++ {
				if mf := prog.MethodValue(mset.At(i)); mf != nil {
					if mfn := mf.Name(); len(mfn) > 0 {
						if iu := unicode.IsUpper(rune(mfn[0])); iu || *nonExp {
							funcs = append(funcs, mf)
							//fmt.Printf("DEBUG method %v %v\n", mfn, mf)
						}
					}
				}
			}
		}
	}
	return funcs
}
예제 #5
0
파일: util.go 프로젝트: nickng/dingo-hunter
// GetMainPkg returns main package of a command.
func MainPkg(prog *ssa.Program) *ssa.Package {
	pkgs := prog.AllPackages()
	for _, pkg := range pkgs {
		if pkg.Pkg.Name() == "main" {
			return pkg
		}
	}
	return nil // Not found
}
예제 #6
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
}
예제 #7
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)
}
예제 #8
0
// FindQueryMethods locates all methods in the given package (assumed to be
// package database/sql) with a string parameter named "query".
func FindQueryMethods(sql *types.Package, ssa *ssa.Program) []*QueryMethod {
	methods := make([]*QueryMethod, 0)
	scope := sql.Scope()
	for _, name := range scope.Names() {
		o := scope.Lookup(name)
		if !o.Exported() {
			continue
		}
		if _, ok := o.(*types.TypeName); !ok {
			continue
		}
		n := o.Type().(*types.Named)
		for i := 0; i < n.NumMethods(); i++ {
			m := n.Method(i)
			if !m.Exported() {
				continue
			}
			s := m.Type().(*types.Signature)
			if num, ok := FuncHasQuery(s); ok {
				methods = append(methods, &QueryMethod{
					Func:     m,
					SSA:      ssa.FuncValue(m),
					ArgCount: s.Params().Len(),
					Param:    num,
				})
			}
		}
	}
	return methods
}
예제 #9
0
func checkFuncValue(t *testing.T, prog *ssa.Program, obj *types.Func) {
	fn := prog.FuncValue(obj)
	// fmt.Printf("FuncValue(%s) = %s\n", obj, fn) // debugging
	if fn == nil {
		if obj.Name() != "interfaceMethod" {
			t.Errorf("FuncValue(%s) == nil", obj)
		}
		return
	}
	if fnobj := fn.Object(); fnobj != obj {
		t.Errorf("FuncValue(%s).Object() == %s; value was %s",
			obj, fnobj, fn.Name())
		return
	}
	if !types.Identical(fn.Type(), obj.Type()) {
		t.Errorf("FuncValue(%s).Type() == %s", obj, fn.Type())
		return
	}
}
예제 #10
0
func checkConstValue(t *testing.T, prog *ssa.Program, obj *types.Const) {
	c := prog.ConstValue(obj)
	// fmt.Printf("ConstValue(%s) = %s\n", obj, c) // debugging
	if c == nil {
		t.Errorf("ConstValue(%s) == nil", obj)
		return
	}
	if !types.Identical(c.Type(), obj.Type()) {
		t.Errorf("ConstValue(%s).Type() == %s", obj, c.Type())
		return
	}
	if obj.Name() != "nil" {
		if !exact.Compare(c.Value, token.EQL, obj.Val()) {
			t.Errorf("ConstValue(%s).Value (%s) != %s",
				obj, c.Value, obj.Val())
			return
		}
	}
}
예제 #11
0
// findVisibleConsts returns a mapping from each package-level constant assignable to type "error", to nil.
func findVisibleConsts(prog *ssa.Program, qpos *queryPos) map[ssa.Const]*ssa.NamedConst {
	constants := make(map[ssa.Const]*ssa.NamedConst)
	for _, pkg := range prog.AllPackages() {
		for _, mem := range pkg.Members {
			obj, ok := mem.(*ssa.NamedConst)
			if !ok {
				continue
			}
			consttype := obj.Type()
			if !types.AssignableTo(consttype, builtinErrorType) {
				continue
			}
			if !isAccessibleFrom(obj.Object(), qpos.info.Pkg) {
				continue
			}
			constants[*obj.Value] = obj
		}
	}

	return constants
}
예제 #12
0
// findVisibleErrs returns a mapping from each package-level variable of type "error" to nil.
func findVisibleErrs(prog *ssa.Program, qpos *queryPos) map[*ssa.Global]ssa.Value {
	globals := make(map[*ssa.Global]ssa.Value)
	for _, pkg := range prog.AllPackages() {
		for _, mem := range pkg.Members {
			gbl, ok := mem.(*ssa.Global)
			if !ok {
				continue
			}
			gbltype := gbl.Type()
			// globals are always pointers
			if !types.Identical(deref(gbltype), builtinErrorType) {
				continue
			}
			if !isAccessibleFrom(gbl.Object(), qpos.info.Pkg) {
				continue
			}
			globals[gbl] = nil
		}
	}
	return globals
}
예제 #13
0
func checkVarValue(t *testing.T, prog *ssa.Program, pkg *ssa.Package, ref []ast.Node, obj *types.Var, expKind string, wantAddr bool) {
	// The prefix of all assertions messages.
	prefix := fmt.Sprintf("VarValue(%s @ L%d)",
		obj, prog.Fset.Position(ref[0].Pos()).Line)

	v, gotAddr := prog.VarValue(obj, pkg, ref)

	// Kind is the concrete type of the ssa Value.
	gotKind := "nil"
	if v != nil {
		gotKind = fmt.Sprintf("%T", v)[len("*ssa."):]
	}

	// fmt.Printf("%s = %v (kind %q; expect %q) wantAddr=%t gotAddr=%t\n", prefix, v, gotKind, expKind, wantAddr, gotAddr) // debugging

	// Check the kinds match.
	// "nil" indicates expected failure (e.g. optimized away).
	if expKind != gotKind {
		t.Errorf("%s concrete type == %s, want %s", prefix, gotKind, expKind)
	}

	// Check the types match.
	// If wantAddr, the expected type is the object's address.
	if v != nil {
		expType := obj.Type()
		if wantAddr {
			expType = types.NewPointer(expType)
			if !gotAddr {
				t.Errorf("%s: got value, want address", prefix)
			}
		} else if gotAddr {
			t.Errorf("%s: got address, want value", prefix)
		}
		if !types.Identical(v.Type(), expType) {
			t.Errorf("%s.Type() == %s, want %s", prefix, v.Type(), expType)
		}
	}
}
예제 #14
0
파일: guru.go 프로젝트: tsandall/opa
// 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
}
예제 #15
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)
}
예제 #16
0
파일: main.go 프로젝트: tarm/gounused
// 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
}
예제 #17
0
파일: func.go 프로젝트: nickng/dingo-hunter
func findMethod(prog *ssa.Program, meth *types.Func, typ types.Type) *ssa.Function {
	if meth != nil {
		fmt.Fprintf(os.Stderr, "     ^ finding method for type: %s pkg: %s name: %s\n", typ.String(), meth.Pkg().Name(), meth.Name())
	}
	return prog.LookupMethod(typ, meth.Pkg(), meth.Name())
}
예제 #18
0
파일: main.go 프로젝트: akwick/ssaview
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
}