mirror of
https://github.com/golang/go
synced 2024-11-18 22:04:43 -07:00
115 lines
3.5 KiB
Go
115 lines
3.5 KiB
Go
|
package pointer
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"go/token"
|
||
|
|
||
|
"code.google.com/p/go.tools/ssa"
|
||
|
)
|
||
|
|
||
|
// TODO(adonovan): move the CallGraph, CallGraphNode, CallSite types
|
||
|
// into a separate package 'callgraph', and make them pure interfaces
|
||
|
// capable of supporting several implementations (context-sensitive
|
||
|
// and insensitive PTA, RTA, etc).
|
||
|
|
||
|
// ---------- CallGraphNode ----------
|
||
|
|
||
|
// A CallGraphNode is a context-sensitive representation of a node in
|
||
|
// the callgraph. In other words, there may be multiple nodes
|
||
|
// representing a single *Function, depending on the contexts in which
|
||
|
// it is called. The identity of the node is therefore important.
|
||
|
//
|
||
|
type CallGraphNode interface {
|
||
|
Func() *ssa.Function // the function this node represents
|
||
|
String() string // diagnostic description of this callgraph node
|
||
|
}
|
||
|
|
||
|
type cgnode struct {
|
||
|
fn *ssa.Function
|
||
|
obj nodeid // start of this contour's object block
|
||
|
}
|
||
|
|
||
|
func (n *cgnode) Func() *ssa.Function {
|
||
|
return n.fn
|
||
|
}
|
||
|
|
||
|
func (n *cgnode) String() string {
|
||
|
return fmt.Sprintf("cg%d:%s", n.obj, n.fn)
|
||
|
}
|
||
|
|
||
|
// ---------- CallSite ----------
|
||
|
|
||
|
// A CallSite is a context-sensitive representation of a function call
|
||
|
// site in the program.
|
||
|
//
|
||
|
type CallSite interface {
|
||
|
Caller() CallGraphNode // the enclosing context of this call
|
||
|
Pos() token.Pos // source position; token.NoPos for synthetic calls
|
||
|
Description() string // UI description of call kind; see (*ssa.CallCommon).Description
|
||
|
String() string // diagnostic description of this callsite
|
||
|
}
|
||
|
|
||
|
// A callsite represents a single function or method callsite within a
|
||
|
// function. callsites never represent calls to built-ins; they are
|
||
|
// handled as intrinsics.
|
||
|
//
|
||
|
type callsite struct {
|
||
|
caller *cgnode // the origin of the call
|
||
|
targets nodeid // pts(targets) contains identities of all called functions.
|
||
|
instr ssa.CallInstruction // optional call instruction; provides IsInvoke, position, etc.
|
||
|
pos token.Pos // position, if instr == nil, i.e. synthetic callsites.
|
||
|
}
|
||
|
|
||
|
// Caller returns the node in the callgraph from which this call originated.
|
||
|
func (c *callsite) Caller() CallGraphNode {
|
||
|
return c.caller
|
||
|
}
|
||
|
|
||
|
// Description returns a description of this kind of call, in the
|
||
|
// manner of ssa.CallCommon.Description().
|
||
|
//
|
||
|
func (c *callsite) Description() string {
|
||
|
if c.instr != nil {
|
||
|
return c.instr.Common().Description()
|
||
|
}
|
||
|
return "synthetic function call"
|
||
|
}
|
||
|
|
||
|
// Pos returns the source position of this callsite, or token.NoPos if implicit.
|
||
|
func (c *callsite) Pos() token.Pos {
|
||
|
if c.instr != nil {
|
||
|
return c.instr.Pos()
|
||
|
}
|
||
|
return c.pos
|
||
|
}
|
||
|
|
||
|
func (c *callsite) String() string {
|
||
|
// TODO(adonovan): provide more info, e.g. target of static
|
||
|
// call, arguments, location.
|
||
|
return c.Description()
|
||
|
}
|
||
|
|
||
|
// ---------- CallGraph ----------
|
||
|
|
||
|
// CallGraph is a forward directed graph of functions labelled by an
|
||
|
// arbitrary site within the caller.
|
||
|
//
|
||
|
// CallGraph.AddEdge may be used as the Context.Call callback for
|
||
|
// clients that wish to construct a call graph.
|
||
|
//
|
||
|
// TODO(adonovan): this is just a starting point. Add options to
|
||
|
// control whether we record no callsite, an arbitrary callsite, or
|
||
|
// all callsites for a given graph edge. Also, this could live in
|
||
|
// another package since it's just a client utility.
|
||
|
//
|
||
|
type CallGraph map[CallGraphNode]map[CallGraphNode]CallSite
|
||
|
|
||
|
func (cg CallGraph) AddEdge(site CallSite, caller, callee CallGraphNode) {
|
||
|
callees := cg[caller]
|
||
|
if callees == nil {
|
||
|
callees = make(map[CallGraphNode]CallSite)
|
||
|
cg[caller] = callees
|
||
|
}
|
||
|
callees[callee] = site // save an arbitrary site
|
||
|
}
|