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.
23 "golang.org/x/tools/go/callgraph"
24 "golang.org/x/tools/go/callgraph/rta"
25 "golang.org/x/tools/go/loader"
26 "golang.org/x/tools/go/ssa"
27 "golang.org/x/tools/go/ssa/ssautil"
30 var inputs = []string{
36 func expectation(f *ast.File) (string, token.Pos) {
37 for _, c := range f.Comments {
38 text := strings.TrimSpace(c.Text())
39 if t := strings.TrimPrefix(text, "WANT:\n"); t != text {
43 return "", token.NoPos
46 // TestRTA runs RTA on each file in inputs, prints the results, and
47 // compares it with the golden results embedded in the WANT comment at
48 // the end of the file.
50 // The results string consists of two parts: the set of dynamic call
51 // edges, "f --> g", one per line, and the set of reachable functions,
52 // one per line. Each set is sorted.
54 func TestRTA(t *testing.T) {
55 for _, filename := range inputs {
56 content, err := ioutil.ReadFile(filename)
58 t.Errorf("couldn't read file '%s': %s", filename, err)
62 conf := loader.Config{
63 ParserMode: parser.ParseComments,
65 f, err := conf.ParseFile(filename, content)
71 want, pos := expectation(f)
72 if pos == token.NoPos {
73 t.Errorf("No WANT: comment in %s", filename)
77 conf.CreateFromFiles("main", f)
78 iprog, err := conf.Load()
84 prog := ssautil.CreateProgram(iprog, 0)
85 mainPkg := prog.Package(iprog.Created[0].Pkg)
88 res := rta.Analyze([]*ssa.Function{
93 if got := printResult(res, mainPkg.Pkg); got != want {
94 t.Errorf("%s: got:\n%s\nwant:\n%s",
95 prog.Fset.Position(pos), got, want)
100 func printResult(res *rta.Result, from *types.Package) string {
103 writeSorted := func(ss []string) {
105 for _, s := range ss {
106 fmt.Fprintf(&buf, " %s\n", s)
110 buf.WriteString("Dynamic calls\n")
112 callgraph.GraphVisitEdges(res.CallGraph, func(e *callgraph.Edge) error {
113 if strings.Contains(e.Description(), "dynamic") {
114 edges = append(edges, fmt.Sprintf("%s --> %s",
115 e.Caller.Func.RelString(from),
116 e.Callee.Func.RelString(from)))
122 buf.WriteString("Reachable functions\n")
123 var reachable []string
124 for f := range res.Reachable {
125 reachable = append(reachable, f.RelString(from))
127 writeSorted(reachable)
129 buf.WriteString("Reflect types\n")
131 res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) {
132 if value == false { // accessible to reflection
133 rtypes = append(rtypes, types.TypeString(key, types.RelativeTo(from)))
138 return strings.TrimSpace(buf.String())