Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / callgraph / rta / rta_test.go
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.
4
5 //lint:file-ignore SA1019 go/callgraph's test suite is built around the deprecated go/loader. We'll leave fixing that to upstream.
6
7 // No testdata on Android.
8
9 // +build !android
10
11 package rta_test
12
13 import (
14         "bytes"
15         "fmt"
16         "go/ast"
17         "go/parser"
18         "go/token"
19         "go/types"
20         "io/ioutil"
21         "sort"
22         "strings"
23         "testing"
24
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"
30 )
31
32 var inputs = []string{
33         "testdata/func.go",
34         "testdata/rtype.go",
35         "testdata/iface.go",
36 }
37
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 {
42                         return t, c.Pos()
43                 }
44         }
45         return "", token.NoPos
46 }
47
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.
51 //
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.
55 //
56 func TestRTA(t *testing.T) {
57         for _, filename := range inputs {
58                 content, err := ioutil.ReadFile(filename)
59                 if err != nil {
60                         t.Errorf("couldn't read file '%s': %s", filename, err)
61                         continue
62                 }
63
64                 conf := loader.Config{
65                         ParserMode: parser.ParseComments,
66                 }
67                 f, err := conf.ParseFile(filename, content)
68                 if err != nil {
69                         t.Error(err)
70                         continue
71                 }
72
73                 want, pos := expectation(f)
74                 if pos == token.NoPos {
75                         t.Errorf("No WANT: comment in %s", filename)
76                         continue
77                 }
78
79                 conf.CreateFromFiles("main", f)
80                 iprog, err := conf.Load()
81                 if err != nil {
82                         t.Error(err)
83                         continue
84                 }
85
86                 prog := irutil.CreateProgram(iprog, 0)
87                 mainPkg := prog.Package(iprog.Created[0].Pkg)
88                 prog.Build()
89
90                 res := rta.Analyze([]*ir.Function{
91                         mainPkg.Func("main"),
92                         mainPkg.Func("init"),
93                 }, true)
94
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)
98                 }
99         }
100 }
101
102 func printResult(res *rta.Result, from *types.Package) string {
103         var buf bytes.Buffer
104
105         writeSorted := func(ss []string) {
106                 sort.Strings(ss)
107                 for _, s := range ss {
108                         fmt.Fprintf(&buf, "  %s\n", s)
109                 }
110         }
111
112         buf.WriteString("Dynamic calls\n")
113         var edges []string
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)))
119                 }
120                 return nil
121         })
122         writeSorted(edges)
123
124         buf.WriteString("Reachable functions\n")
125         var reachable []string
126         for f := range res.Reachable {
127                 reachable = append(reachable, f.RelString(from))
128         }
129         writeSorted(reachable)
130
131         buf.WriteString("Reflect types\n")
132         var rtypes []string
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)))
136                 }
137         })
138         writeSorted(rtypes)
139
140         return strings.TrimSpace(buf.String())
141 }