@@ -16,7 +16,7 @@ import (
16
16
"go/parser"
17
17
"go/token"
18
18
"go/types"
19
- "io/ioutil "
19
+ "os "
20
20
"sort"
21
21
"strings"
22
22
"testing"
@@ -26,6 +26,7 @@ import (
26
26
"golang.org/x/tools/go/loader"
27
27
"golang.org/x/tools/go/ssa"
28
28
"golang.org/x/tools/go/ssa/ssautil"
29
+ "golang.org/x/tools/internal/typeparams"
29
30
)
30
31
31
32
var inputs = []string {
@@ -53,16 +54,7 @@ func expectation(f *ast.File) (string, token.Pos) {
53
54
// one per line. Each set is sorted.
54
55
func TestRTA (t * testing.T ) {
55
56
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 )
57
+ prog , f , mainPkg , err := loadProgInfo (filename , ssa .BuilderMode (0 ))
66
58
if err != nil {
67
59
t .Error (err )
68
60
continue
@@ -74,30 +66,77 @@ func TestRTA(t *testing.T) {
74
66
continue
75
67
}
76
68
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
69
res := rta .Analyze ([]* ssa.Function {
89
70
mainPkg .Func ("main" ),
90
71
mainPkg .Func ("init" ),
91
72
}, true )
92
73
93
- if got := printResult (res , mainPkg .Pkg ); got != want {
74
+ if got := printResult (res , mainPkg .Pkg , "dynamic" , "Dynamic calls" ); got != want {
94
75
t .Errorf ("%s: got:\n %s\n want:\n %s" ,
95
76
prog .Fset .Position (pos ), got , want )
96
77
}
97
78
}
98
79
}
99
80
100
- func printResult (res * rta.Result , from * types.Package ) string {
81
+ // TestRTAGenerics is TestRTA specialized for testing generics.
82
+ func TestRTAGenerics (t * testing.T ) {
83
+ if ! typeparams .Enabled {
84
+ t .Skip ("TestRTAGenerics requires type parameters" )
85
+ }
86
+
87
+ filename := "testdata/generics.go"
88
+ prog , f , mainPkg , err := loadProgInfo (filename , ssa .InstantiateGenerics )
89
+ if err != nil {
90
+ t .Fatal (err )
91
+ }
92
+
93
+ want , pos := expectation (f )
94
+ if pos == token .NoPos {
95
+ t .Fatalf ("No WANT: comment in %s" , filename )
96
+ }
97
+
98
+ res := rta .Analyze ([]* ssa.Function {
99
+ mainPkg .Func ("main" ),
100
+ mainPkg .Func ("init" ),
101
+ }, true )
102
+
103
+ if got := printResult (res , mainPkg .Pkg , "" , "All calls" ); got != want {
104
+ t .Errorf ("%s: got:\n %s\n want:\n %s" ,
105
+ prog .Fset .Position (pos ), got , want )
106
+ }
107
+ }
108
+
109
+ func loadProgInfo (filename string , mode ssa.BuilderMode ) (* ssa.Program , * ast.File , * ssa.Package , error ) {
110
+ content , err := os .ReadFile (filename )
111
+ if err != nil {
112
+ return nil , nil , nil , fmt .Errorf ("couldn't read file '%s': %s" , filename , err )
113
+ }
114
+
115
+ conf := loader.Config {
116
+ ParserMode : parser .ParseComments ,
117
+ }
118
+ f , err := conf .ParseFile (filename , content )
119
+ if err != nil {
120
+ return nil , nil , nil , err
121
+ }
122
+
123
+ conf .CreateFromFiles ("main" , f )
124
+ iprog , err := conf .Load ()
125
+ if err != nil {
126
+ return nil , nil , nil , err
127
+ }
128
+
129
+ prog := ssautil .CreateProgram (iprog , mode )
130
+ prog .Build ()
131
+
132
+ return prog , f , prog .Package (iprog .Created [0 ].Pkg ), nil
133
+ }
134
+
135
+ // printResult returns a string representation of res, i.e., call graph,
136
+ // reachable functions, and reflect types. For call graph, only edges
137
+ // whose description contains edgeMatch are returned and their string
138
+ // representation is prefixed with a desc line.
139
+ func printResult (res * rta.Result , from * types.Package , edgeMatch , desc string ) string {
101
140
var buf bytes.Buffer
102
141
103
142
writeSorted := func (ss []string ) {
@@ -107,10 +146,10 @@ func printResult(res *rta.Result, from *types.Package) string {
107
146
}
108
147
}
109
148
110
- buf .WriteString ("Dynamic calls \n " )
149
+ buf .WriteString (desc + " \n " )
111
150
var edges []string
112
151
callgraph .GraphVisitEdges (res .CallGraph , func (e * callgraph.Edge ) error {
113
- if strings .Contains (e .Description (), "dynamic" ) {
152
+ if strings .Contains (e .Description (), edgeMatch ) {
114
153
edges = append (edges , fmt .Sprintf ("%s --> %s" ,
115
154
e .Caller .Func .RelString (from ),
116
155
e .Callee .Func .RelString (from )))
0 commit comments