2013-08-27 16:49:13 -06:00
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2013-08-27 15:58:26 -06:00
|
|
|
package oracle
|
|
|
|
|
|
|
|
import (
|
2013-09-03 13:29:02 -06:00
|
|
|
"go/token"
|
2013-11-13 07:11:10 -07:00
|
|
|
"sort"
|
2013-08-27 15:58:26 -06:00
|
|
|
|
2014-01-16 12:04:19 -07:00
|
|
|
"code.google.com/p/go.tools/go/callgraph"
|
2014-01-16 07:33:58 -07:00
|
|
|
"code.google.com/p/go.tools/go/ssa"
|
2013-09-24 13:08:14 -06:00
|
|
|
"code.google.com/p/go.tools/oracle/serial"
|
2013-08-27 15:58:26 -06:00
|
|
|
)
|
|
|
|
|
2014-01-16 12:04:19 -07:00
|
|
|
// doCallgraph displays the entire callgraph of the current program.
|
2013-08-27 15:58:26 -06:00
|
|
|
//
|
|
|
|
// TODO(adonovan): add options for restricting the display to a region
|
2013-09-03 13:29:02 -06:00
|
|
|
// of interest: function, package, subgraph, dirtree, goroutine, etc.
|
|
|
|
//
|
2013-09-25 15:17:42 -06:00
|
|
|
// TODO(adonovan): add an option to partition edges by call site.
|
|
|
|
//
|
2013-09-03 13:29:02 -06:00
|
|
|
// TODO(adonovan): elide nodes for synthetic functions?
|
2013-08-27 15:58:26 -06:00
|
|
|
//
|
2014-01-16 12:04:19 -07:00
|
|
|
func doCallgraph(o *Oracle, _ *QueryPos) (queryResult, error) {
|
2013-08-27 15:58:26 -06:00
|
|
|
buildSSA(o)
|
|
|
|
|
|
|
|
// Run the pointer analysis and build the complete callgraph.
|
2013-12-13 08:04:55 -07:00
|
|
|
o.ptaConfig.BuildCallGraph = true
|
2013-09-25 15:17:42 -06:00
|
|
|
ptares := ptrAnalysis(o)
|
2013-09-03 13:29:02 -06:00
|
|
|
|
2013-08-27 15:58:26 -06:00
|
|
|
return &callgraphResult{
|
2013-09-25 15:17:42 -06:00
|
|
|
callgraph: ptares.CallGraph,
|
2013-08-27 15:58:26 -06:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type callgraphResult struct {
|
2014-02-20 09:57:48 -07:00
|
|
|
callgraph *callgraph.Graph
|
2013-08-27 15:58:26 -06:00
|
|
|
}
|
|
|
|
|
2013-09-03 13:29:02 -06:00
|
|
|
func (r *callgraphResult) display(printf printfFunc) {
|
|
|
|
printf(nil, `
|
2013-08-27 15:58:26 -06:00
|
|
|
Below is a call graph of the entire program.
|
|
|
|
The numbered nodes form a spanning tree.
|
|
|
|
Non-numbered nodes indicate back- or cross-edges to the node whose
|
|
|
|
number follows in parentheses.
|
|
|
|
`)
|
2013-11-13 07:11:10 -07:00
|
|
|
|
2014-02-20 09:57:48 -07:00
|
|
|
printed := make(map[*callgraph.Node]int)
|
|
|
|
var print func(caller *callgraph.Node, indent int)
|
|
|
|
print = func(caller *callgraph.Node, indent int) {
|
2013-11-13 07:11:10 -07:00
|
|
|
if num, ok := printed[caller]; !ok {
|
|
|
|
num = len(printed)
|
|
|
|
printed[caller] = num
|
|
|
|
|
|
|
|
// Sort the children into name order for deterministic* output.
|
|
|
|
// (*mostly: anon funcs' names are not globally unique.)
|
|
|
|
var funcs funcsByName
|
2014-02-20 09:57:48 -07:00
|
|
|
for callee := range callgraph.CalleesOf(caller) {
|
|
|
|
funcs = append(funcs, callee.Func)
|
2013-11-13 07:11:10 -07:00
|
|
|
}
|
|
|
|
sort.Sort(funcs)
|
|
|
|
|
2014-02-20 09:57:48 -07:00
|
|
|
printf(caller.Func, "%d\t%*s%s", num, 4*indent, "", caller.Func)
|
2013-11-13 07:11:10 -07:00
|
|
|
for _, callee := range funcs {
|
2014-02-20 09:57:48 -07:00
|
|
|
print(r.callgraph.Nodes[callee], indent+1)
|
2013-09-03 13:29:02 -06:00
|
|
|
}
|
|
|
|
} else {
|
2014-02-20 09:57:48 -07:00
|
|
|
printf(caller, "\t%*s%s (%d)", 4*indent, "", caller.Func, num)
|
2013-09-03 13:29:02 -06:00
|
|
|
}
|
|
|
|
}
|
2014-02-20 09:57:48 -07:00
|
|
|
print(r.callgraph.Root, 0)
|
2013-09-03 13:29:02 -06:00
|
|
|
}
|
|
|
|
|
2013-11-13 07:11:10 -07:00
|
|
|
type funcsByName []*ssa.Function
|
|
|
|
|
|
|
|
func (s funcsByName) Len() int { return len(s) }
|
|
|
|
func (s funcsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
|
|
func (s funcsByName) Less(i, j int) bool { return s[i].String() < s[j].String() }
|
|
|
|
|
2013-09-24 13:08:14 -06:00
|
|
|
func (r *callgraphResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
2014-02-20 09:57:48 -07:00
|
|
|
cg := make([]serial.CallGraph, len(r.callgraph.Nodes))
|
|
|
|
for _, n := range r.callgraph.Nodes {
|
|
|
|
j := &cg[n.ID]
|
|
|
|
fn := n.Func
|
2013-09-03 13:29:02 -06:00
|
|
|
j.Name = fn.String()
|
2013-09-10 12:11:42 -06:00
|
|
|
j.Pos = fset.Position(fn.Pos()).String()
|
2014-01-16 12:04:19 -07:00
|
|
|
for callee := range callgraph.CalleesOf(n) {
|
2014-02-20 09:57:48 -07:00
|
|
|
j.Children = append(j.Children, callee.ID)
|
2013-09-03 13:29:02 -06:00
|
|
|
}
|
2014-01-15 20:55:52 -07:00
|
|
|
sort.Ints(j.Children)
|
2013-09-03 13:29:02 -06:00
|
|
|
}
|
|
|
|
res.Callgraph = cg
|
2013-08-27 15:58:26 -06:00
|
|
|
}
|