// 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 }
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 } }
// 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) }