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 //lint:file-ignore SA1019 go/callgraph's test suite is built around the deprecated go/loader. We'll leave fixing that to upstream.
7 // No testdata on Android.
25 "honnef.co/go/tools/go/callgraph"
26 "honnef.co/go/tools/go/callgraph/rta"
27 "honnef.co/go/tools/go/ir"
28 "honnef.co/go/tools/go/ir/irutil"
30 "golang.org/x/tools/go/loader"
33 var inputs = []string{
39 func expectation(f *ast.File) (string, token.Pos) {
40 for _, c := range f.Comments {
41 text := strings.TrimSpace(c.Text())
42 if t := strings.TrimPrefix(text, "WANT:\n"); t != text {
46 return "", token.NoPos
49 // TestRTA runs RTA on each file in inputs, prints the results, and
50 // compares it with the golden results embedded in the WANT comment at
51 // the end of the file.
53 // The results string consists of two parts: the set of dynamic call
54 // edges, "f --> g", one per line, and the set of reachable functions,
55 // one per line. Each set is sorted.
57 func TestRTA(t *testing.T) {
58 for _, filename := range inputs {
59 content, err := ioutil.ReadFile(filename)
61 t.Errorf("couldn't read file '%s': %s", filename, err)
65 conf := loader.Config{
66 ParserMode: parser.ParseComments,
68 f, err := conf.ParseFile(filename, content)
74 want, pos := expectation(f)
75 if pos == token.NoPos {
76 t.Errorf("No WANT: comment in %s", filename)
80 conf.CreateFromFiles("main", f)
81 iprog, err := conf.Load()
87 prog := irutil.CreateProgram(iprog, 0)
88 mainPkg := prog.Package(iprog.Created[0].Pkg)
91 res := rta.Analyze([]*ir.Function{
96 if got := printResult(res, mainPkg.Pkg); got != want {
97 t.Errorf("%s: got:\n%s\nwant:\n%s",
98 prog.Fset.Position(pos), got, want)
103 func printResult(res *rta.Result, from *types.Package) string {
106 writeSorted := func(ss []string) {
108 for _, s := range ss {
109 fmt.Fprintf(&buf, " %s\n", s)
113 buf.WriteString("Dynamic calls\n")
115 callgraph.GraphVisitEdges(res.CallGraph, func(e *callgraph.Edge) error {
116 if strings.Contains(e.Description(), "dynamic") {
117 edges = append(edges, fmt.Sprintf("%s --> %s",
118 e.Caller.Func.RelString(from),
119 e.Callee.Func.RelString(from)))
125 buf.WriteString("Reachable functions\n")
126 var reachable []string
127 for f := range res.Reachable {
128 reachable = append(reachable, f.RelString(from))
130 writeSorted(reachable)
132 buf.WriteString("Reflect types\n")
134 res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) {
135 if value == false { // accessible to reflection
136 rtypes = append(rtypes, types.TypeString(key, types.RelativeTo(from)))
141 return strings.TrimSpace(buf.String())