// 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 }