func (a *analysis) addCallees(site ssa.CallInstruction, fns []*ssa.Function) {
	v := calleesJSON{
		Descr:   site.Common().Description(),
		Callees: []anchorJSON{},  
	}
	var this *types.Package  
	if p := site.Parent().Package(); p != nil {
		this = p.Pkg
	}
	for _, fn := range fns {
		v.Callees = append(v.Callees, anchorJSON{
			Text: prettyFunc(this, fn),
			Href: a.posURL(funcToken(fn), len("func")),
		})
	}
	fi, offset := a.fileAndOffset(site.Common().Pos())
	fi.addLink(aLink{
		start:   offset,
		end:     offset + len("("),
		title:   fmt.Sprintf("%d callees", len(v.Callees)),
		onclick: fmt.Sprintf("onClickCallees(%d)", fi.addData(v)),
	})
}
addCallees adds client data and links for the facts that site calls fns.
package analysis
import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"log"
	"math/big"
	"sort"
	"golang.org/x/tools/go/callgraph"
	"golang.org/x/tools/go/ssa"
)
func (a *analysis) doCallgraph(cg *callgraph.Graph) {
	log.Print("Deleting synthetic nodes...")
	cg.DeleteSyntheticNodes()
	log.Print("Synthetic nodes deleted")
	for _, n := range cg.Nodes {
		a.pcgAddNode(n.Func)
	}
	for _, pcg := range a.pcgs {
		pcg.sortNodes()
	}
	calledFuncs := make(map[ssa.CallInstruction]map[*ssa.Function]bool)
	callingSites := make(map[*ssa.Function]map[ssa.CallInstruction]bool)
	for _, n := range cg.Nodes {
		for _, e := range n.Out {
			if e.Site == nil {
				continue  
			}
			callee := e.Callee.Func
			a.pcgAddEdge(n.Func, callee)
			if callee.Synthetic != "" {
				continue  
			}
			if e.Site.Common().StaticCallee() == nil {
				lparen := e.Site.Common().Pos()
				if lparen != token.NoPos {
					fns := calledFuncs[e.Site]
					if fns == nil {
						fns = make(map[*ssa.Function]bool)
						calledFuncs[e.Site] = fns
					}
					fns[callee] = true
				}
			}
			fns := callingSites[callee]
			if fns == nil {
				fns = make(map[ssa.CallInstruction]bool)
				callingSites[callee] = fns
			}
			fns[e.Site] = true
		}
	}
	log.Print("Callees...")
	for site, fns := range calledFuncs {
		var funcs funcsByPos
		for fn := range fns {
			funcs = append(funcs, fn)
		}
		sort.Sort(funcs)
		a.addCallees(site, funcs)
	}
	log.Print("Callers...")
	for callee, sites := range callingSites {
		pos := funcToken(callee)
		if pos == token.NoPos {
			log.Printf("CALLERS: skipping %s: no pos", callee)
			continue
		}
		var this *types.Package  
		if callee.Pkg != nil {
			this = callee.Pkg.Pkg
		}
		sitesByParent := make(map[*ssa.Function]sitesByPos)
		for site := range sites {
			fn := site.Parent()
			sitesByParent[fn] = append(sitesByParent[fn], site)
		}
		var funcs funcsByPos
		for fn := range sitesByParent {
			funcs = append(funcs, fn)
		}
		sort.Sort(funcs)
		v := callersJSON{
			Callee:  callee.String(),
			Callers: []callerJSON{},  
		}
		for _, fn := range funcs {
			caller := callerJSON{
				Func:  prettyFunc(this, fn),
				Sites: []anchorJSON{},  
			}
			sites := sitesByParent[fn]
			sort.Sort(sites)
			for _, site := range sites {
				pos := site.Common().Pos()
				if pos != token.NoPos {
					caller.Sites = append(caller.Sites, anchorJSON{
						Text: fmt.Sprintf("%d", a.prog.Fset.Position(pos).Line),
						Href: a.posURL(pos, len("(")),
					})
				}
			}
			v.Callers = append(v.Callers, caller)
		}
		fi, offset := a.fileAndOffset(pos)
		fi.addLink(aLink{
			start:   offset,
			end:     offset + len("func"),
			title:   fmt.Sprintf("%d callers", len(sites)),
			onclick: fmt.Sprintf("onClickCallers(%d)", fi.addData(v)),
		})
	}
	log.Print("Package call graph...")
	for pkg, pcg := range a.pcgs {
		index := make(map[string]int)
		for i, n := range pcg.nodes {
			if i == 0 || n.fn.Object() == nil || !n.fn.Object().Exported() {
				continue
			}
			recv := n.fn.Signature.Recv()
			if recv == nil || deref(recv.Type()).(*types.Named).Obj().Exported() {
				roots := &pcg.nodes[0].edges
				roots.SetBit(roots, i, 1)
			}
			index[n.fn.RelString(pkg.Pkg)] = i
		}
		json := a.pcgJSON(pcg)
		a.result.pkgInfo(pkg.Pkg.Path()).setCallGraph(json, index)
	}
}