Example #1
0
func findCallees(o *Oracle, site ssa.CallInstruction) ([]*ssa.Function, error) {
	// Avoid running the pointer analysis for static calls.
	if callee := site.Common().StaticCallee(); callee != nil {
		switch callee.String() {
		case "runtime.SetFinalizer", "(reflect.Value).Call":
			// The PTA treats calls to these intrinsics as dynamic.
			// TODO(adonovan): avoid reliance on PTA internals.

		default:
			return []*ssa.Function{callee}, nil // singleton
		}
	}

	// Dynamic call: use pointer analysis.
	o.ptaConfig.BuildCallGraph = true
	callgraph := ptrAnalysis(o).CallGraph

	// Find all call edges from the site.
	calleesMap := make(map[*ssa.Function]bool)
	var foundCGNode bool
	for _, n := range callgraph.Nodes() {
		if n.Func() == site.Parent() {
			foundCGNode = true
			for _, edge := range n.Edges() {
				if edge.Site == site {
					calleesMap[edge.Callee.Func()] = true
				}
			}
		}
	}
	if !foundCGNode {
		return nil, fmt.Errorf("this call site is unreachable in this analysis")
	}

	// Discard context, de-duplicate and sort.
	funcs := make([]*ssa.Function, 0, len(calleesMap))
	for f := range calleesMap {
		funcs = append(funcs, f)
	}
	sort.Sort(byFuncPos(funcs))
	return funcs, nil
}