Skip to content

Commit 075ae7d

Browse files
committed
go/callgraph/vta: add basic tests for range-over-func
The tests check the callees at the call to yield and type flow out of the range-over-func iterator. If needed, a test for defer will be added in a follow-up CL. Change-Id: Ic9208ac0824a36fb50879730e8ec9398b9b6e284 Reviewed-on: https://go-review.googlesource.com/c/tools/+/611395 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Tim King <[email protected]>
1 parent 2c7aaab commit 075ae7d

File tree

2 files changed

+107
-9
lines changed

2 files changed

+107
-9
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright 2024 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+
// go:build ignore
6+
7+
package testdata
8+
9+
type I interface {
10+
Foo()
11+
}
12+
13+
type A struct{}
14+
15+
func (a A) Foo() {}
16+
17+
type B struct{}
18+
19+
func (b B) Foo() {}
20+
21+
type C struct{}
22+
23+
func (c C) Foo() {} // Test that this is not called.
24+
25+
type iset []I
26+
27+
func (i iset) All() func(func(I) bool) {
28+
return func(yield func(I) bool) {
29+
for _, v := range i {
30+
if !yield(v) {
31+
return
32+
}
33+
}
34+
}
35+
}
36+
37+
var x = iset([]I{A{}, B{}})
38+
39+
func X() {
40+
for i := range x.All() {
41+
i.Foo()
42+
}
43+
}
44+
45+
func Y() I {
46+
for i := range x.All() {
47+
return i
48+
}
49+
return nil
50+
}
51+
52+
func Bar() {
53+
X()
54+
y := Y()
55+
y.Foo()
56+
}
57+
58+
// Relevant SSA:
59+
//func X$1(I) bool:
60+
// t0 = *jump$1
61+
// t1 = t0 == 0:int
62+
// if t1 goto 1 else 2
63+
//1:
64+
// *jump$1 = -1:int
65+
// t2 = invoke arg0.Foo()
66+
// *jump$1 = 0:int
67+
// return true:bool
68+
//2:
69+
// t3 = make interface{} <- string ("yield function ca...":string) interface{}
70+
// panic t3
71+
//
72+
//func All$1(yield func(I) bool):
73+
// t0 = *i
74+
// t1 = len(t0)
75+
// jump 1
76+
//1:
77+
// t2 = phi [0: -1:int, 2: t3] #rangeindex
78+
// t3 = t2 + 1:int
79+
// t4 = t3 < t1
80+
// if t4 goto 2 else 3
81+
//2:
82+
// t5 = &t0[t3]
83+
// t6 = *t5
84+
// t7 = yield(t6)
85+
// if t7 goto 1 else 4
86+
//
87+
//func Bar():
88+
// t0 = X()
89+
// t1 = Y()
90+
// t2 = invoke t1.Foo()
91+
// return
92+
93+
// WANT:
94+
// Bar: X() -> X; Y() -> Y; invoke t1.Foo() -> A.Foo, B.Foo
95+
// X$1: invoke arg0.Foo() -> A.Foo, B.Foo
96+
// All$1: yield(t6) -> X$1, Y$1

go/callgraph/vta/vta_test.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:debug gotypesalias=1
6+
57
package vta
68

79
import (
@@ -15,7 +17,7 @@ import (
1517
"golang.org/x/tools/go/callgraph/cha"
1618
"golang.org/x/tools/go/ssa"
1719
"golang.org/x/tools/go/ssa/ssautil"
18-
"golang.org/x/tools/internal/aliases"
20+
"golang.org/x/tools/internal/testenv"
1921
)
2022

2123
func TestVTACallGraph(t *testing.T) {
@@ -27,7 +29,7 @@ func TestVTACallGraph(t *testing.T) {
2729
cmp.Diff(got, want)) // to aid debugging
2830
}
2931

30-
for _, file := range []string{
32+
files := []string{
3133
"testdata/src/callgraph_static.go",
3234
"testdata/src/callgraph_ho.go",
3335
"testdata/src/callgraph_interfaces.go",
@@ -38,14 +40,14 @@ func TestVTACallGraph(t *testing.T) {
3840
"testdata/src/callgraph_recursive_types.go",
3941
"testdata/src/callgraph_issue_57756.go",
4042
"testdata/src/callgraph_comma_maps.go",
41-
"testdata/src/callgraph_type_aliases.go",
42-
} {
43-
t.Run(file, func(t *testing.T) {
44-
// https://github.com/golang/go/issues/68799
45-
if !aliases.Enabled() && file == "testdata/src/callgraph_type_aliases.go" {
46-
t.Skip("callgraph_type_aliases.go requires gotypesalias=1")
47-
}
43+
"testdata/src/callgraph_type_aliases.go", // https://github.com/golang/go/issues/68799
44+
}
45+
if testenv.Go1Point() >= 23 {
46+
files = append(files, "testdata/src/callgraph_range_over_func.go")
47+
}
4848

49+
for _, file := range files {
50+
t.Run(file, func(t *testing.T) {
4951
prog, want, err := testProg(file, ssa.BuilderMode(0))
5052
if err != nil {
5153
t.Fatalf("couldn't load test file '%s': %s", file, err)

0 commit comments

Comments
 (0)