OLD | NEW |
1 // Copyright 2013 The Go Authors. All rights reserved. | 1 // Copyright 2013 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package oracle | 5 package oracle |
6 | 6 |
7 import ( | 7 import ( |
| 8 "go/token" |
| 9 |
| 10 "code.google.com/p/go.tools/oracle/json" |
8 "code.google.com/p/go.tools/pointer" | 11 "code.google.com/p/go.tools/pointer" |
9 "code.google.com/p/go.tools/ssa" | 12 "code.google.com/p/go.tools/ssa" |
10 ) | 13 ) |
11 | 14 |
12 // Callers reports the possible callers of the function | 15 // Callers reports the possible callers of the function |
13 // immediately enclosing the specified source location. | 16 // immediately enclosing the specified source location. |
14 // | 17 // |
15 // TODO(adonovan): if a caller is a wrapper, show the caller's caller. | 18 // TODO(adonovan): if a caller is a wrapper, show the caller's caller. |
16 // | 19 // |
17 func callers(o *oracle) (queryResult, error) { | 20 func callers(o *oracle) (queryResult, error) { |
18 pkg := o.prog.Package(o.queryPkgInfo.Pkg) | 21 pkg := o.prog.Package(o.queryPkgInfo.Pkg) |
19 if pkg == nil { | 22 if pkg == nil { |
20 return nil, o.errorf(o.queryPath[0], "no SSA package") | 23 return nil, o.errorf(o.queryPath[0], "no SSA package") |
21 } | 24 } |
22 if !ssa.HasEnclosingFunction(pkg, o.queryPath) { | 25 if !ssa.HasEnclosingFunction(pkg, o.queryPath) { |
23 return nil, o.errorf(o.queryPath[0], "this position is not insid
e a function") | 26 return nil, o.errorf(o.queryPath[0], "this position is not insid
e a function") |
24 } | 27 } |
25 | 28 |
26 buildSSA(o) | 29 buildSSA(o) |
27 | 30 |
28 target := ssa.EnclosingFunction(pkg, o.queryPath) | 31 target := ssa.EnclosingFunction(pkg, o.queryPath) |
29 if target == nil { | 32 if target == nil { |
30 return nil, o.errorf(o.queryPath[0], "no SSA function built for
this location (dead code?)") | 33 return nil, o.errorf(o.queryPath[0], "no SSA function built for
this location (dead code?)") |
31 } | 34 } |
32 | 35 |
33 // Run the pointer analysis, recording each | 36 // Run the pointer analysis, recording each |
34 // call found to originate from target. | 37 // call found to originate from target. |
35 » var calls []callersCall | 38 » var calls []pointer.CallSite |
36 » o.config.Call = func(site pointer.CallSite, caller, callee pointer.CallG
raphNode) { | 39 » o.config.Call = func(site pointer.CallSite, callee pointer.CallGraphNode
) { |
37 if callee.Func() == target { | 40 if callee.Func() == target { |
38 » » » calls = append(calls, callersCall{site, caller}) | 41 » » » calls = append(calls, site) |
39 } | 42 } |
40 } | 43 } |
| 44 // TODO(adonovan): sort calls, to ensure test determinism. |
| 45 |
41 root := ptrAnalysis(o) | 46 root := ptrAnalysis(o) |
42 | 47 |
43 return &callersResult{ | 48 return &callersResult{ |
44 target: target, | 49 target: target, |
45 root: root, | 50 root: root, |
46 calls: calls, | 51 calls: calls, |
47 }, nil | 52 }, nil |
48 } | 53 } |
49 | 54 |
50 type callersResult struct { | 55 type callersResult struct { |
51 target *ssa.Function | 56 target *ssa.Function |
52 root pointer.CallGraphNode | 57 root pointer.CallGraphNode |
53 » calls []callersCall | 58 » calls []pointer.CallSite |
54 } | 59 } |
55 | 60 |
56 type callersCall struct { | 61 func (r *callersResult) display(printf printfFunc) { |
57 » site pointer.CallSite | |
58 » caller pointer.CallGraphNode | |
59 } | |
60 | |
61 func (r *callersResult) display(o *oracle) { | |
62 if r.calls == nil { | 62 if r.calls == nil { |
63 » » o.printf(r.target, "%s is not reachable in this program.", r.tar
get) | 63 » » printf(r.target, "%s is not reachable in this program.", r.targe
t) |
64 } else { | 64 } else { |
65 » » o.printf(r.target, "%s is called from these %d sites:", r.target
, len(r.calls)) | 65 » » printf(r.target, "%s is called from these %d sites:", r.target,
len(r.calls)) |
66 » » // TODO(adonovan): sort, to ensure test determinism. | 66 » » for _, site := range r.calls { |
67 » » for _, call := range r.calls { | 67 » » » if site.Caller() == r.root { |
68 » » » if call.caller == r.root { | 68 » » » » printf(r.target, "the root of the call graph") |
69 » » » » o.printf(r.target, "the root of the call graph") | |
70 } else { | 69 } else { |
71 » » » » o.printf(call.site, "\t%s from %s", | 70 » » » » printf(site, "\t%s from %s", site.Description(),
site.Caller().Func()) |
72 » » » » » call.site.Description(), call.caller.Fun
c()) | |
73 } | 71 } |
74 } | 72 } |
75 } | 73 } |
| 74 } |
76 | 75 |
| 76 func (r *callersResult) toJSON(res *json.Result, fset *token.FileSet) { |
| 77 var callers []json.Caller |
| 78 for _, site := range r.calls { |
| 79 var c json.Caller |
| 80 c.Caller = site.Caller().Func().String() |
| 81 if site.Caller() == r.root { |
| 82 c.Desc = "synthetic call" |
| 83 } else { |
| 84 c.Pos = site.Caller().Func().Prog.Fset.Position(site.Pos
()).String() |
| 85 c.Desc = site.Description() |
| 86 } |
| 87 callers = append(callers, c) |
| 88 } |
| 89 res.Callers = callers |
77 } | 90 } |
OLD | NEW |