Skip to content

Commit 01bd772

Browse files
adonovangopherbot
authored andcommitted
go/callgraph: rewrite tests to use go/packages not go/loader
The cha_test.loadPackages function has moved to testfiles.LoadPackages. Updates golang/go#69556 Change-Id: I5b1657388cb4d6ca435d1ab3a7cbf9cd264a0e7b Reviewed-on: https://go-review.googlesource.com/c/tools/+/614679 Reviewed-by: Tim King <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Alan Donovan <[email protected]>
1 parent f8ce005 commit 01bd772

File tree

14 files changed

+232
-221
lines changed

14 files changed

+232
-221
lines changed

go/callgraph/callgraph_test.go

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package callgraph_test
55

66
import (
7-
"log"
87
"sync"
98
"testing"
109

@@ -13,9 +12,10 @@ import (
1312
"golang.org/x/tools/go/callgraph/rta"
1413
"golang.org/x/tools/go/callgraph/static"
1514
"golang.org/x/tools/go/callgraph/vta"
16-
"golang.org/x/tools/go/loader"
1715
"golang.org/x/tools/go/ssa"
1816
"golang.org/x/tools/go/ssa/ssautil"
17+
"golang.org/x/tools/internal/testfiles"
18+
"golang.org/x/tools/txtar"
1919
)
2020

2121
// Benchmarks comparing different callgraph algorithms implemented in
@@ -47,7 +47,12 @@ import (
4747
// CHA callgraph.
4848
// * All algorithms are unsound w.r.t. reflection.
4949

50-
const httpEx = `package main
50+
const httpEx = `
51+
-- go.mod --
52+
module x.io
53+
54+
-- main.go --
55+
package main
5156
5257
import (
5358
"fmt"
@@ -70,23 +75,12 @@ var (
7075
main *ssa.Function
7176
)
7277

73-
func example() (*ssa.Program, *ssa.Function) {
78+
func example(t testing.TB) (*ssa.Program, *ssa.Function) {
7479
once.Do(func() {
75-
var conf loader.Config
76-
f, err := conf.ParseFile("<input>", httpEx)
77-
if err != nil {
78-
log.Fatal(err)
79-
}
80-
conf.CreateFromFiles(f.Name.Name, f)
81-
82-
lprog, err := conf.Load()
83-
if err != nil {
84-
log.Fatalf("test 'package %s': Load: %s", f.Name.Name, err)
85-
}
86-
prog = ssautil.CreateProgram(lprog, ssa.InstantiateGenerics)
80+
pkgs := testfiles.LoadPackages(t, txtar.Parse([]byte(httpEx)), ".")
81+
prog, ssapkgs := ssautil.Packages(pkgs, ssa.InstantiateGenerics)
8782
prog.Build()
88-
89-
main = prog.Package(lprog.Created[0].Pkg).Members["main"].(*ssa.Function)
83+
main = ssapkgs[0].Members["main"].(*ssa.Function)
9084
})
9185
return prog, main
9286
}
@@ -106,7 +100,7 @@ func logStats(b *testing.B, cnd bool, name string, cg *callgraph.Graph, main *ss
106100

107101
func BenchmarkStatic(b *testing.B) {
108102
b.StopTimer()
109-
prog, main := example()
103+
prog, main := example(b)
110104
b.StartTimer()
111105

112106
for i := 0; i < b.N; i++ {
@@ -117,7 +111,7 @@ func BenchmarkStatic(b *testing.B) {
117111

118112
func BenchmarkCHA(b *testing.B) {
119113
b.StopTimer()
120-
prog, main := example()
114+
prog, main := example(b)
121115
b.StartTimer()
122116

123117
for i := 0; i < b.N; i++ {
@@ -128,7 +122,7 @@ func BenchmarkCHA(b *testing.B) {
128122

129123
func BenchmarkRTA(b *testing.B) {
130124
b.StopTimer()
131-
_, main := example()
125+
_, main := example(b)
132126
b.StartTimer()
133127

134128
for i := 0; i < b.N; i++ {
@@ -140,7 +134,7 @@ func BenchmarkRTA(b *testing.B) {
140134

141135
func BenchmarkVTA(b *testing.B) {
142136
b.StopTimer()
143-
prog, main := example()
137+
prog, main := example(b)
144138
b.StartTimer()
145139

146140
for i := 0; i < b.N; i++ {
@@ -151,7 +145,7 @@ func BenchmarkVTA(b *testing.B) {
151145

152146
func BenchmarkVTA2(b *testing.B) {
153147
b.StopTimer()
154-
prog, main := example()
148+
prog, main := example(b)
155149
b.StartTimer()
156150

157151
for i := 0; i < b.N; i++ {
@@ -163,7 +157,7 @@ func BenchmarkVTA2(b *testing.B) {
163157

164158
func BenchmarkVTA3(b *testing.B) {
165159
b.StopTimer()
166-
prog, main := example()
160+
prog, main := example(b)
167161
b.StartTimer()
168162

169163
for i := 0; i < b.N; i++ {
@@ -176,7 +170,7 @@ func BenchmarkVTA3(b *testing.B) {
176170

177171
func BenchmarkVTAAlt(b *testing.B) {
178172
b.StopTimer()
179-
prog, main := example()
173+
prog, main := example(b)
180174
b.StartTimer()
181175

182176
for i := 0; i < b.N; i++ {
@@ -188,7 +182,7 @@ func BenchmarkVTAAlt(b *testing.B) {
188182

189183
func BenchmarkVTAAlt2(b *testing.B) {
190184
b.StopTimer()
191-
prog, main := example()
185+
prog, main := example(b)
192186
b.StartTimer()
193187

194188
for i := 0; i < b.N; i++ {

go/callgraph/cha/cha_test.go

Lines changed: 70 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,22 @@ import (
1313
"bytes"
1414
"fmt"
1515
"go/ast"
16-
"go/build"
17-
"go/parser"
1816
"go/token"
1917
"go/types"
2018
"os"
19+
"path/filepath"
2120
"sort"
2221
"strings"
2322
"testing"
2423

25-
"golang.org/x/tools/go/buildutil"
2624
"golang.org/x/tools/go/callgraph"
2725
"golang.org/x/tools/go/callgraph/cha"
28-
"golang.org/x/tools/go/loader"
26+
"golang.org/x/tools/go/packages"
2927
"golang.org/x/tools/go/ssa"
3028
"golang.org/x/tools/go/ssa/ssautil"
29+
"golang.org/x/tools/internal/testenv"
30+
"golang.org/x/tools/internal/testfiles"
31+
"golang.org/x/tools/txtar"
3132
)
3233

3334
var inputs = []string{
@@ -52,45 +53,38 @@ func expectation(f *ast.File) (string, token.Pos) {
5253
// the WANT comment at the end of the file.
5354
func TestCHA(t *testing.T) {
5455
for _, filename := range inputs {
55-
prog, f, mainPkg, err := loadProgInfo(filename, ssa.InstantiateGenerics)
56-
if err != nil {
57-
t.Error(err)
58-
continue
59-
}
56+
pkg, ssapkg := loadFile(t, filename, ssa.InstantiateGenerics)
6057

61-
want, pos := expectation(f)
58+
want, pos := expectation(pkg.Syntax[0])
6259
if pos == token.NoPos {
6360
t.Error(fmt.Errorf("No WANT: comment in %s", filename))
6461
continue
6562
}
6663

67-
cg := cha.CallGraph(prog)
64+
cg := cha.CallGraph(ssapkg.Prog)
6865

69-
if got := printGraph(cg, mainPkg.Pkg, "dynamic", "Dynamic calls"); got != want {
66+
if got := printGraph(cg, pkg.Types, "dynamic", "Dynamic calls"); got != want {
7067
t.Errorf("%s: got:\n%s\nwant:\n%s",
71-
prog.Fset.Position(pos), got, want)
68+
ssapkg.Prog.Fset.Position(pos), got, want)
7269
}
7370
}
7471
}
7572

7673
// TestCHAGenerics is TestCHA tailored for testing generics,
7774
func TestCHAGenerics(t *testing.T) {
7875
filename := "testdata/generics.go"
79-
prog, f, mainPkg, err := loadProgInfo(filename, ssa.InstantiateGenerics)
80-
if err != nil {
81-
t.Fatal(err)
82-
}
76+
pkg, ssapkg := loadFile(t, filename, ssa.InstantiateGenerics)
8377

84-
want, pos := expectation(f)
78+
want, pos := expectation(pkg.Syntax[0])
8579
if pos == token.NoPos {
8680
t.Fatal(fmt.Errorf("No WANT: comment in %s", filename))
8781
}
8882

89-
cg := cha.CallGraph(prog)
83+
cg := cha.CallGraph(ssapkg.Prog)
9084

91-
if got := printGraph(cg, mainPkg.Pkg, "", "All calls"); got != want {
85+
if got := printGraph(cg, pkg.Types, "", "All calls"); got != want {
9286
t.Errorf("%s: got:\n%s\nwant:\n%s",
93-
prog.Fset.Position(pos), got, want)
87+
ssapkg.Prog.Fset.Position(pos), got, want)
9488
}
9589
}
9690

@@ -109,39 +103,43 @@ func TestCHAUnexported(t *testing.T) {
109103
// We use CHA to build a callgraph, then check that it has the
110104
// appropriate set of edges.
111105

112-
main := `package main
113-
import "p2"
114-
type I1 interface { m() }
115-
type S1 struct { p2.I2 }
116-
func (s S1) m() { }
117-
func main() {
118-
var s S1
119-
var o I1 = s
120-
o.m()
121-
p2.Foo(s)
122-
}`
123-
124-
p2 := `package p2
125-
type I2 interface { m() }
126-
type S2 struct { }
127-
func (s S2) m() { }
128-
func Foo(i I2) { i.m() }`
106+
const src = `
107+
-- go.mod --
108+
module x.io
109+
go 1.18
110+
111+
-- main/main.go --
112+
package main
113+
114+
import "x.io/p2"
115+
116+
type I1 interface { m() }
117+
type S1 struct { p2.I2 }
118+
func (s S1) m() { }
119+
func main() {
120+
var s S1
121+
var o I1 = s
122+
o.m()
123+
p2.Foo(s)
124+
}
125+
126+
-- p2/p2.go --
127+
package p2
128+
129+
type I2 interface { m() }
130+
type S2 struct { }
131+
func (s S2) m() { }
132+
func Foo(i I2) { i.m() }
133+
`
129134

130135
want := `All calls
131-
main.init --> p2.init
132-
main.main --> (main.S1).m
133-
main.main --> p2.Foo
134-
p2.Foo --> (p2.S2).m`
136+
x.io/main.init --> x.io/p2.init
137+
x.io/main.main --> (x.io/main.S1).m
138+
x.io/main.main --> x.io/p2.Foo
139+
x.io/p2.Foo --> (x.io/p2.S2).m`
135140

136-
conf := loader.Config{
137-
Build: fakeContext(map[string]string{"main": main, "p2": p2}),
138-
}
139-
conf.Import("main")
140-
iprog, err := conf.Load()
141-
if err != nil {
142-
t.Fatalf("Load failed: %v", err)
143-
}
144-
prog := ssautil.CreateProgram(iprog, ssa.InstantiateGenerics)
141+
pkgs := testfiles.LoadPackages(t, txtar.Parse([]byte(src)), "./...")
142+
prog, _ := ssautil.Packages(pkgs, ssa.InstantiateGenerics)
145143
prog.Build()
146144

147145
cg := cha.CallGraph(prog)
@@ -154,39 +152,35 @@ func TestCHAUnexported(t *testing.T) {
154152
}
155153
}
156154

157-
// Simplifying wrapper around buildutil.FakeContext for single-file packages.
158-
func fakeContext(pkgs map[string]string) *build.Context {
159-
pkgs2 := make(map[string]map[string]string)
160-
for path, content := range pkgs {
161-
pkgs2[path] = map[string]string{"x.go": content}
162-
}
163-
return buildutil.FakeContext(pkgs2)
164-
}
155+
// loadFile loads a built SSA package for a single-file "x.io/main" package.
156+
// (Ideally all uses would be converted over to txtar files with explicit go.mod files.)
157+
func loadFile(t testing.TB, filename string, mode ssa.BuilderMode) (*packages.Package, *ssa.Package) {
158+
testenv.NeedsGoPackages(t)
165159

166-
func loadProgInfo(filename string, mode ssa.BuilderMode) (*ssa.Program, *ast.File, *ssa.Package, error) {
167-
content, err := os.ReadFile(filename)
160+
data, err := os.ReadFile(filename)
168161
if err != nil {
169-
return nil, nil, nil, fmt.Errorf("couldn't read file '%s': %s", filename, err)
162+
t.Fatal(err)
170163
}
171-
172-
conf := loader.Config{
173-
ParserMode: parser.ParseComments,
164+
dir := t.TempDir()
165+
cfg := &packages.Config{
166+
Mode: packages.LoadAllSyntax,
167+
Dir: dir,
168+
Overlay: map[string][]byte{
169+
filepath.Join(dir, "go.mod"): []byte("module x.io\ngo 1.22"),
170+
filepath.Join(dir, "main/main.go"): data,
171+
},
172+
Env: append(os.Environ(), "GO111MODULES=on", "GOPATH=", "GOWORK=off", "GOPROXY=off"),
174173
}
175-
f, err := conf.ParseFile(filename, content)
174+
pkgs, err := packages.Load(cfg, "./main")
176175
if err != nil {
177-
return nil, nil, nil, err
176+
t.Fatal(err)
178177
}
179-
180-
conf.CreateFromFiles("main", f)
181-
iprog, err := conf.Load()
182-
if err != nil {
183-
return nil, nil, nil, err
178+
if num := packages.PrintErrors(pkgs); num > 0 {
179+
t.Fatalf("packages contained %d errors", num)
184180
}
185-
186-
prog := ssautil.CreateProgram(iprog, mode)
181+
prog, ssapkgs := ssautil.Packages(pkgs, mode)
187182
prog.Build()
188-
189-
return prog, f, prog.Package(iprog.Created[0].Pkg), nil
183+
return pkgs[0], ssapkgs[0]
190184
}
191185

192186
// printGraph returns a string representation of cg involving only edges

go/callgraph/cha/testdata/func.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// +build ignore
2-
31
package main
42

53
// Test of dynamic function calls; no interfaces.

go/callgraph/cha/testdata/generics.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
//go:build ignore
2-
// +build ignore
3-
41
package main
52

63
// Test of generic function calls.
@@ -38,12 +35,12 @@ func f(h func(), g func(I), k func(A), a A, b B) {
3835
// (*A).Foo --> (A).Foo
3936
// (*B).Foo --> (B).Foo
4037
// f --> Bar
41-
// f --> instantiated[main.A]
42-
// f --> instantiated[main.A]
43-
// f --> instantiated[main.B]
38+
// f --> instantiated[x.io/main.A]
39+
// f --> instantiated[x.io/main.A]
40+
// f --> instantiated[x.io/main.B]
4441
// instantiated --> (*A).Foo
4542
// instantiated --> (*B).Foo
4643
// instantiated --> (A).Foo
4744
// instantiated --> (B).Foo
48-
// instantiated[main.A] --> (A).Foo
49-
// instantiated[main.B] --> (B).Foo
45+
// instantiated[x.io/main.A] --> (A).Foo
46+
// instantiated[x.io/main.B] --> (B).Foo

go/callgraph/cha/testdata/iface.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// +build ignore
2-
31
package main
42

53
// Test of interface calls. None of the concrete types are ever

go/callgraph/cha/testdata/recv.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// +build ignore
2-
31
package main
42

53
type I interface {

0 commit comments

Comments
 (0)