Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / 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 // No testdata on Android.
6
7 // +build !android
8
9 package rta_test
10
11 import (
12         "bytes"
13         "fmt"
14         "go/ast"
15         "go/parser"
16         "go/token"
17         "go/types"
18         "io/ioutil"
19         "sort"
20         "strings"
21         "testing"
22
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"
28 )
29
30 var inputs = []string{
31         "testdata/func.go",
32         "testdata/rtype.go",
33         "testdata/iface.go",
34 }
35
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 {
40                         return t, c.Pos()
41                 }
42         }
43         return "", token.NoPos
44 }
45
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.
49 //
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.
53 //
54 func TestRTA(t *testing.T) {
55         for _, filename := range inputs {
56                 content, err := ioutil.ReadFile(filename)
57                 if err != nil {
58                         t.Errorf("couldn't read file '%s': %s", filename, err)
59                         continue
60                 }
61
62                 conf := loader.Config{
63                         ParserMode: parser.ParseComments,
64                 }
65                 f, err := conf.ParseFile(filename, content)
66                 if err != nil {
67                         t.Error(err)
68                         continue
69                 }
70
71                 want, pos := expectation(f)
72                 if pos == token.NoPos {
73                         t.Errorf("No WANT: comment in %s", filename)
74                         continue
75                 }
76
77                 conf.CreateFromFiles("main", f)
78                 iprog, err := conf.Load()
79                 if err != nil {
80                         t.Error(err)
81                         continue
82                 }
83
84                 prog := ssautil.CreateProgram(iprog, 0)
85                 mainPkg := prog.Package(iprog.Created[0].Pkg)
86                 prog.Build()
87
88                 res := rta.Analyze([]*ssa.Function{
89                         mainPkg.Func("main"),
90                         mainPkg.Func("init"),
91                 }, true)
92
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)
96                 }
97         }
98 }
99
100 func printResult(res *rta.Result, from *types.Package) string {
101         var buf bytes.Buffer
102
103         writeSorted := func(ss []string) {
104                 sort.Strings(ss)
105                 for _, s := range ss {
106                         fmt.Fprintf(&buf, "  %s\n", s)
107                 }
108         }
109
110         buf.WriteString("Dynamic calls\n")
111         var edges []string
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)))
117                 }
118                 return nil
119         })
120         writeSorted(edges)
121
122         buf.WriteString("Reachable functions\n")
123         var reachable []string
124         for f := range res.Reachable {
125                 reachable = append(reachable, f.RelString(from))
126         }
127         writeSorted(reachable)
128
129         buf.WriteString("Reflect types\n")
130         var rtypes []string
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)))
134                 }
135         })
136         writeSorted(rtypes)
137
138         return strings.TrimSpace(buf.String())
139 }