// CallGraph uses the VTA algorithm to compute call graph for all functions // f:true in funcs. VTA refines the results of initial call graph and uses it // to establish interprocedural type flow. If initial is nil, VTA uses a more // efficient approach to construct a CHA call graph. // // The resulting graph does not have a root node. // // CallGraph does not make any assumptions on initial types global variables // and function/method inputs can have. CallGraph is then sound, modulo use of // reflection and unsafe, if the initial call graph is sound. func CallGraph(funcs map[*ssa.Function]bool, initial *callgraph.Graph) *callgraph.Graph { … } type constructor … func (c *constructor) construct(funcs map[*ssa.Function]bool) *callgraph.Graph { … } func (c *constructor) constrct(g *callgraph.Graph, f *ssa.Function) { … } // resolves computes the set of functions to which VTA resolves `c`. The resolved // functions are intersected with functions to which `c.initial` resolves `c`. func (c *constructor) resolves(call ssa.CallInstruction) []*ssa.Function { … } // resolve returns a set of functions `c` resolves to based on the // type propagation results in `types`. func resolve(c ssa.CallInstruction, types propTypeMap, cache methodCache) map[*ssa.Function]empty { … } // propFunc returns the functions modeled with the propagation type `p` // assigned to call site `c`. If no such function exists, nil is returned. func propFunc(p propType, c ssa.CallInstruction, cache methodCache) []*ssa.Function { … } type methodCache … // methods returns methods of a type `t` named `name`. First consults // `mc` and otherwise queries `prog` for the method. If no such method // exists, nil is returned. func (mc methodCache) methods(t types.Type, name string, prog *ssa.Program) []*ssa.Function { … }