.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / 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 //go:build !android
8 // +build !android
9
10 package rta_test
11
12 import (
13         "bytes"
14         "fmt"
15         "go/ast"
16         "go/parser"
17         "go/token"
18         "go/types"
19         "io/ioutil"
20         "sort"
21         "strings"
22         "testing"
23
24         "golang.org/x/tools/go/callgraph"
25         "golang.org/x/tools/go/callgraph/rta"
26         "golang.org/x/tools/go/loader"
27         "golang.org/x/tools/go/ssa"
28         "golang.org/x/tools/go/ssa/ssautil"
29 )
30
31 var inputs = []string{
32         "testdata/func.go",
33         "testdata/rtype.go",
34         "testdata/iface.go",
35 }
36
37 func expectation(f *ast.File) (string, token.Pos) {
38         for _, c := range f.Comments {
39                 text := strings.TrimSpace(c.Text())
40                 if t := strings.TrimPrefix(text, "WANT:\n"); t != text {
41                         return t, c.Pos()
42                 }
43         }
44         return "", token.NoPos
45 }
46
47 // TestRTA runs RTA on each file in inputs, prints the results, and
48 // compares it with the golden results embedded in the WANT comment at
49 // the end of the file.
50 //
51 // The results string consists of two parts: the set of dynamic call
52 // edges, "f --> g", one per line, and the set of reachable functions,
53 // one per line.  Each set is sorted.
54 //
55 func TestRTA(t *testing.T) {
56         for _, filename := range inputs {
57                 content, err := ioutil.ReadFile(filename)
58                 if err != nil {
59                         t.Errorf("couldn't read file '%s': %s", filename, err)
60                         continue
61                 }
62
63                 conf := loader.Config{
64                         ParserMode: parser.ParseComments,
65                 }
66                 f, err := conf.ParseFile(filename, content)
67                 if err != nil {
68                         t.Error(err)
69                         continue
70                 }
71
72                 want, pos := expectation(f)
73                 if pos == token.NoPos {
74                         t.Errorf("No WANT: comment in %s", filename)
75                         continue
76                 }
77
78                 conf.CreateFromFiles("main", f)
79                 iprog, err := conf.Load()
80                 if err != nil {
81                         t.Error(err)
82                         continue
83                 }
84
85                 prog := ssautil.CreateProgram(iprog, 0)
86                 mainPkg := prog.Package(iprog.Created[0].Pkg)
87                 prog.Build()
88
89                 res := rta.Analyze([]*ssa.Function{
90                         mainPkg.Func("main"),
91                         mainPkg.Func("init"),
92                 }, true)
93
94                 if got := printResult(res, mainPkg.Pkg); got != want {
95                         t.Errorf("%s: got:\n%s\nwant:\n%s",
96                                 prog.Fset.Position(pos), got, want)
97                 }
98         }
99 }
100
101 func printResult(res *rta.Result, from *types.Package) string {
102         var buf bytes.Buffer
103
104         writeSorted := func(ss []string) {
105                 sort.Strings(ss)
106                 for _, s := range ss {
107                         fmt.Fprintf(&buf, "  %s\n", s)
108                 }
109         }
110
111         buf.WriteString("Dynamic calls\n")
112         var edges []string
113         callgraph.GraphVisitEdges(res.CallGraph, func(e *callgraph.Edge) error {
114                 if strings.Contains(e.Description(), "dynamic") {
115                         edges = append(edges, fmt.Sprintf("%s --> %s",
116                                 e.Caller.Func.RelString(from),
117                                 e.Callee.Func.RelString(from)))
118                 }
119                 return nil
120         })
121         writeSorted(edges)
122
123         buf.WriteString("Reachable functions\n")
124         var reachable []string
125         for f := range res.Reachable {
126                 reachable = append(reachable, f.RelString(from))
127         }
128         writeSorted(reachable)
129
130         buf.WriteString("Reflect types\n")
131         var rtypes []string
132         res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) {
133                 if value == false { // accessible to reflection
134                         rtypes = append(rtypes, types.TypeString(key, types.RelativeTo(from)))
135                 }
136         })
137         writeSorted(rtypes)
138
139         return strings.TrimSpace(buf.String())
140 }