...

Source file src/golang.org/x/tools/go/callgraph/callgraph.go

Documentation: golang.org/x/tools/go/callgraph

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  /*
     6  Package callgraph defines the call graph and various algorithms
     7  and utilities to operate on it.
     8  
     9  A call graph is a labelled directed graph whose nodes represent
    10  functions and whose edge labels represent syntactic function call
    11  sites.  The presence of a labelled edge (caller, site, callee)
    12  indicates that caller may call callee at the specified call site.
    13  
    14  A call graph is a multigraph: it may contain multiple edges (caller,
    15  *, callee) connecting the same pair of nodes, so long as the edges
    16  differ by label; this occurs when one function calls another function
    17  from multiple call sites.  Also, it may contain multiple edges
    18  (caller, site, *) that differ only by callee; this indicates a
    19  polymorphic call.
    20  
    21  A SOUND call graph is one that overapproximates the dynamic calling
    22  behaviors of the program in all possible executions.  One call graph
    23  is more PRECISE than another if it is a smaller overapproximation of
    24  the dynamic behavior.
    25  
    26  All call graphs have a synthetic root node which is responsible for
    27  calling main() and init().
    28  
    29  Calls to built-in functions (e.g. panic, println) are not represented
    30  in the call graph; they are treated like built-in operators of the
    31  language.
    32  */
    33  package callgraph // import "golang.org/x/tools/go/callgraph"
    34  
    35  // TODO(adonovan): add a function to eliminate wrappers from the
    36  // callgraph, preserving topology.
    37  // More generally, we could eliminate "uninteresting" nodes such as
    38  // nodes from packages we don't care about.
    39  
    40  // TODO(zpavlinovic): decide how callgraphs handle calls to and from generic function bodies.
    41  
    42  import (
    43  	"fmt"
    44  	"go/token"
    45  
    46  	"golang.org/x/tools/go/ssa"
    47  )
    48  
    49  // A Graph represents a call graph.
    50  //
    51  // A graph may contain nodes that are not reachable from the root.
    52  // If the call graph is sound, such nodes indicate unreachable
    53  // functions.
    54  type Graph struct {
    55  	Root  *Node                   // the distinguished root node
    56  	Nodes map[*ssa.Function]*Node // all nodes by function
    57  }
    58  
    59  // New returns a new Graph with the specified root node.
    60  func New(root *ssa.Function) *Graph {
    61  	g := &Graph{Nodes: make(map[*ssa.Function]*Node)}
    62  	g.Root = g.CreateNode(root)
    63  	return g
    64  }
    65  
    66  // CreateNode returns the Node for fn, creating it if not present.
    67  func (g *Graph) CreateNode(fn *ssa.Function) *Node {
    68  	n, ok := g.Nodes[fn]
    69  	if !ok {
    70  		n = &Node{Func: fn, ID: len(g.Nodes)}
    71  		g.Nodes[fn] = n
    72  	}
    73  	return n
    74  }
    75  
    76  // A Node represents a node in a call graph.
    77  type Node struct {
    78  	Func *ssa.Function // the function this node represents
    79  	ID   int           // 0-based sequence number
    80  	In   []*Edge       // unordered set of incoming call edges (n.In[*].Callee == n)
    81  	Out  []*Edge       // unordered set of outgoing call edges (n.Out[*].Caller == n)
    82  }
    83  
    84  func (n *Node) String() string {
    85  	return fmt.Sprintf("n%d:%s", n.ID, n.Func)
    86  }
    87  
    88  // A Edge represents an edge in the call graph.
    89  //
    90  // Site is nil for edges originating in synthetic or intrinsic
    91  // functions, e.g. reflect.Value.Call or the root of the call graph.
    92  type Edge struct {
    93  	Caller *Node
    94  	Site   ssa.CallInstruction
    95  	Callee *Node
    96  }
    97  
    98  func (e Edge) String() string {
    99  	return fmt.Sprintf("%s --> %s", e.Caller, e.Callee)
   100  }
   101  
   102  func (e Edge) Description() string {
   103  	var prefix string
   104  	switch e.Site.(type) {
   105  	case nil:
   106  		return "synthetic call"
   107  	case *ssa.Go:
   108  		prefix = "concurrent "
   109  	case *ssa.Defer:
   110  		prefix = "deferred "
   111  	}
   112  	return prefix + e.Site.Common().Description()
   113  }
   114  
   115  func (e Edge) Pos() token.Pos {
   116  	if e.Site == nil {
   117  		return token.NoPos
   118  	}
   119  	return e.Site.Pos()
   120  }
   121  
   122  // AddEdge adds the edge (caller, site, callee) to the call graph.
   123  // Elimination of duplicate edges is the caller's responsibility.
   124  func AddEdge(caller *Node, site ssa.CallInstruction, callee *Node) {
   125  	e := &Edge{caller, site, callee}
   126  	callee.In = append(callee.In, e)
   127  	caller.Out = append(caller.Out, e)
   128  }
   129  

View as plain text