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 "golang.org/x/tools/go/loader"
26 "honnef.co/go/tools/callgraph"
27 "honnef.co/go/tools/callgraph/rta"
28 "honnef.co/go/tools/ir"
29 "honnef.co/go/tools/ir/irutil"
32 var inputs = []string{
38 func expectation(f *ast.File) (string, token.Pos) {
39 for _, c := range f.Comments {
40 text := strings.TrimSpace(c.Text())
41 if t := strings.TrimPrefix(text, "WANT:\n"); t != text {
45 return "", token.NoPos
48 // TestRTA runs RTA on each file in inputs, prints the results, and
49 // compares it with the golden results embedded in the WANT comment at
50 // the end of the file.
52 // The results string consists of two parts: the set of dynamic call
53 // edges, "f --> g", one per line, and the set of reachable functions,
54 // one per line. Each set is sorted.
56 func TestRTA(t *testing.T) {
57 for _, filename := range inputs {
58 content, err := ioutil.ReadFile(filename)
60 t.Errorf("couldn't read file '%s': %s", filename, err)
64 conf := loader.Config{
65 ParserMode: parser.ParseComments,
67 f, err := conf.ParseFile(filename, content)
73 want, pos := expectation(f)
74 if pos == token.NoPos {
75 t.Errorf("No WANT: comment in %s", filename)
79 conf.CreateFromFiles("main", f)
80 iprog, err := conf.Load()
86 prog := irutil.CreateProgram(iprog, 0)
87 mainPkg := prog.Package(iprog.Created[0].Pkg)
90 res := rta.Analyze([]*ir.Function{
95 if got := printResult(res, mainPkg.Pkg); got != want {
96 t.Errorf("%s: got:\n%s\nwant:\n%s",
97 prog.Fset.Position(pos), got, want)
102 func printResult(res *rta.Result, from *types.Package) string {
105 writeSorted := func(ss []string) {
107 for _, s := range ss {
108 fmt.Fprintf(&buf, " %s\n", s)
112 buf.WriteString("Dynamic calls\n")
114 callgraph.GraphVisitEdges(res.CallGraph, func(e *callgraph.Edge) error {
115 if strings.Contains(e.Description(), "dynamic") {
116 edges = append(edges, fmt.Sprintf("%s --> %s",
117 e.Caller.Func.RelString(from),
118 e.Callee.Func.RelString(from)))
124 buf.WriteString("Reachable functions\n")
125 var reachable []string
126 for f := range res.Reachable {
127 reachable = append(reachable, f.RelString(from))
129 writeSorted(reachable)
131 buf.WriteString("Reflect types\n")
133 res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) {
134 if value == false { // accessible to reflection
135 rtypes = append(rtypes, types.TypeString(key, types.RelativeTo(from)))
140 return strings.TrimSpace(buf.String())