// FindNonConstCalls returns the set of callsites of the given set of methods // for which the "query" parameter is not a compile-time constant. func FindNonConstCalls(cg *callgraph.Graph, qms []*QueryMethod) []ssa.CallInstruction { cg.DeleteSyntheticNodes() // package database/sql has a couple helper functions which are thin // wrappers around other sensitive functions. Instead of handling the // general case by tracing down callsites of wrapper functions // recursively, let's just whitelist the functions we're already // tracking, since it happens to be good enough for our use case. okFuncs := make(map[*ssa.Function]struct{}, len(qms)) for _, m := range qms { okFuncs[m.SSA] = struct{}{} } bad := make([]ssa.CallInstruction, 0) for _, m := range qms { node := cg.CreateNode(m.SSA) for _, edge := range node.In { if _, ok := okFuncs[edge.Site.Parent()]; ok { continue } cc := edge.Site.Common() args := cc.Args // The first parameter is occasionally the receiver. if len(args) == m.ArgCount+1 { args = args[1:] } else if len(args) != m.ArgCount { panic("arg count mismatch") } v := args[m.Param] if _, ok := v.(*ssa.Const); !ok { bad = append(bad, edge.Site) } } } return bad }