You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
3.8 KiB

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