blob: af328a9e66595fcf96854beb31a0bf20d4b2fea6 [file] [log] [blame]
// 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.
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, callee CallGraphNode) {
caller := site.Caller()
callees := cg[caller]
if callees == nil {
callees = make(map[CallGraphNode]CallSite)
cg[caller] = callees
}
callees[callee] = site // save an arbitrary site
}