...
1
2
3
4
5 package callgraph
6
7 import "golang.org/x/tools/go/ssa"
8
9
10
11
12
13
14 func CalleesOf(caller *Node) map[*Node]bool {
15 callees := make(map[*Node]bool)
16 for _, e := range caller.Out {
17 callees[e.Callee] = true
18 }
19 return callees
20 }
21
22
23
24
25
26 func GraphVisitEdges(g *Graph, edge func(*Edge) error) error {
27 seen := make(map[*Node]bool)
28 var visit func(n *Node) error
29 visit = func(n *Node) error {
30 if !seen[n] {
31 seen[n] = true
32 for _, e := range n.Out {
33 if err := visit(e.Callee); err != nil {
34 return err
35 }
36 if err := edge(e); err != nil {
37 return err
38 }
39 }
40 }
41 return nil
42 }
43 for _, n := range g.Nodes {
44 if err := visit(n); err != nil {
45 return err
46 }
47 }
48 return nil
49 }
50
51
52
53
54
55 func PathSearch(start *Node, isEnd func(*Node) bool) []*Edge {
56 stack := make([]*Edge, 0, 32)
57 seen := make(map[*Node]bool)
58 var search func(n *Node) []*Edge
59 search = func(n *Node) []*Edge {
60 if !seen[n] {
61 seen[n] = true
62 if isEnd(n) {
63 return stack
64 }
65 for _, e := range n.Out {
66 stack = append(stack, e)
67 if found := search(e.Callee); found != nil {
68 return found
69 }
70 stack = stack[:len(stack)-1]
71 }
72 }
73 return nil
74 }
75 return search(start)
76 }
77
78
79
80
81
82
83
84
85 func (g *Graph) DeleteSyntheticNodes() {
86
87
88
89
90
91
92
93
94
95
96
97
98 edges := make(map[Edge]bool)
99 for _, cgn := range g.Nodes {
100 for _, e := range cgn.Out {
101 edges[*e] = true
102 }
103 }
104 for fn, cgn := range g.Nodes {
105 if cgn == g.Root || isInit(cgn.Func) || fn.Syntax() != nil {
106 continue
107 }
108 for _, eIn := range cgn.In {
109 for _, eOut := range cgn.Out {
110 newEdge := Edge{eIn.Caller, eIn.Site, eOut.Callee}
111 if edges[newEdge] {
112 continue
113 }
114 AddEdge(eIn.Caller, eIn.Site, eOut.Callee)
115 edges[newEdge] = true
116 }
117 }
118 g.DeleteNode(cgn)
119 }
120 }
121
122 func isInit(fn *ssa.Function) bool {
123 return fn.Pkg != nil && fn.Pkg.Func("init") == fn
124 }
125
126
127
128 func (g *Graph) DeleteNode(n *Node) {
129 n.deleteIns()
130 n.deleteOuts()
131 delete(g.Nodes, n.Func)
132 }
133
134
135 func (n *Node) deleteIns() {
136 for _, e := range n.In {
137 removeOutEdge(e)
138 }
139 n.In = nil
140 }
141
142
143 func (n *Node) deleteOuts() {
144 for _, e := range n.Out {
145 removeInEdge(e)
146 }
147 n.Out = nil
148 }
149
150
151 func removeOutEdge(edge *Edge) {
152 caller := edge.Caller
153 n := len(caller.Out)
154 for i, e := range caller.Out {
155 if e == edge {
156
157 caller.Out[i] = caller.Out[n-1]
158 caller.Out[n-1] = nil
159 caller.Out = caller.Out[:n-1]
160 return
161 }
162 }
163 panic("edge not found: " + edge.String())
164 }
165
166
167 func removeInEdge(edge *Edge) {
168 caller := edge.Callee
169 n := len(caller.In)
170 for i, e := range caller.In {
171 if e == edge {
172
173 caller.In[i] = caller.In[n-1]
174 caller.In[n-1] = nil
175 caller.In = caller.In[:n-1]
176 return
177 }
178 }
179 panic("edge not found: " + edge.String())
180 }
181
View as plain text