1 // Copyright 2014 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.
5 // No testdata on Android.
24 "golang.org/x/tools/go/callgraph"
25 "golang.org/x/tools/go/callgraph/rta"
26 "golang.org/x/tools/go/loader"
27 "golang.org/x/tools/go/ssa"
28 "golang.org/x/tools/go/ssa/ssautil"
31 var inputs = []string{
37 func expectation(f *ast.File) (string, token.Pos) {
38 for _, c := range f.Comments {
39 text := strings.TrimSpace(c.Text())
40 if t := strings.TrimPrefix(text, "WANT:\n"); t != text {
44 return "", token.NoPos
47 // TestRTA runs RTA on each file in inputs, prints the results, and
48 // compares it with the golden results embedded in the WANT comment at
49 // the end of the file.
51 // The results string consists of two parts: the set of dynamic call
52 // edges, "f --> g", one per line, and the set of reachable functions,
53 // one per line. Each set is sorted.
55 func TestRTA(t *testing.T) {
56 for _, filename := range inputs {
57 content, err := ioutil.ReadFile(filename)
59 t.Errorf("couldn't read file '%s': %s", filename, err)
63 conf := loader.Config{
64 ParserMode: parser.ParseComments,
66 f, err := conf.ParseFile(filename, content)
72 want, pos := expectation(f)
73 if pos == token.NoPos {
74 t.Errorf("No WANT: comment in %s", filename)
78 conf.CreateFromFiles("main", f)
79 iprog, err := conf.Load()
85 prog := ssautil.CreateProgram(iprog, 0)
86 mainPkg := prog.Package(iprog.Created[0].Pkg)
89 res := rta.Analyze([]*ssa.Function{
94 if got := printResult(res, mainPkg.Pkg); got != want {
95 t.Errorf("%s: got:\n%s\nwant:\n%s",
96 prog.Fset.Position(pos), got, want)
101 func printResult(res *rta.Result, from *types.Package) string {
104 writeSorted := func(ss []string) {
106 for _, s := range ss {
107 fmt.Fprintf(&buf, " %s\n", s)
111 buf.WriteString("Dynamic calls\n")
113 callgraph.GraphVisitEdges(res.CallGraph, func(e *callgraph.Edge) error {
114 if strings.Contains(e.Description(), "dynamic") {
115 edges = append(edges, fmt.Sprintf("%s --> %s",
116 e.Caller.Func.RelString(from),
117 e.Callee.Func.RelString(from)))
123 buf.WriteString("Reachable functions\n")
124 var reachable []string
125 for f := range res.Reachable {
126 reachable = append(reachable, f.RelString(from))
128 writeSorted(reachable)
130 buf.WriteString("Reflect types\n")
132 res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) {
133 if value == false { // accessible to reflection
134 rtypes = append(rtypes, types.TypeString(key, types.RelativeTo(from)))
139 return strings.TrimSpace(buf.String())