mirror of https://github.com/golang/go.git
go/callgraph/vta: adds tests for (instantiated) generics
Updates golang/go#48525 Change-Id: Ia84365d7f48f804f2b397782789706ef6d1d4b86 Reviewed-on: https://go-review.googlesource.com/c/tools/+/402274 Run-TryBot: Zvonimir Pavlinovic <zpavlinovic@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Tim King <taking@google.com>
This commit is contained in:
parent
b44fad8412
commit
dcaea06afc
|
|
@ -13,6 +13,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/callgraph/cha"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/go/ssa/ssautil"
|
||||
)
|
||||
|
||||
|
|
@ -24,7 +25,7 @@ func TestNodeInterface(t *testing.T) {
|
|||
// - global variable "gl"
|
||||
// - "main" function and its
|
||||
// - first register instruction t0 := *gl
|
||||
prog, _, err := testProg("testdata/src/simple.go")
|
||||
prog, _, err := testProg("testdata/src/simple.go", ssa.BuilderMode(0))
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't load testdata/src/simple.go program: %v", err)
|
||||
}
|
||||
|
|
@ -78,7 +79,7 @@ func TestNodeInterface(t *testing.T) {
|
|||
|
||||
func TestVtaGraph(t *testing.T) {
|
||||
// Get the basic type int from a real program.
|
||||
prog, _, err := testProg("testdata/src/simple.go")
|
||||
prog, _, err := testProg("testdata/src/simple.go", ssa.BuilderMode(0))
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't load testdata/src/simple.go program: %v", err)
|
||||
}
|
||||
|
|
@ -191,7 +192,7 @@ func TestVTAGraphConstruction(t *testing.T) {
|
|||
"testdata/src/panic.go",
|
||||
} {
|
||||
t.Run(file, func(t *testing.T) {
|
||||
prog, want, err := testProg(file)
|
||||
prog, want, err := testProg(file, ssa.BuilderMode(0))
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't load test file '%s': %s", file, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func want(f *ast.File) []string {
|
|||
// testProg returns an ssa representation of a program at
|
||||
// `path`, assumed to define package "testdata," and the
|
||||
// test want result as list of strings.
|
||||
func testProg(path string) (*ssa.Program, []string, error) {
|
||||
func testProg(path string, mode ssa.BuilderMode) (*ssa.Program, []string, error) {
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
|
@ -56,7 +56,7 @@ func testProg(path string) (*ssa.Program, []string, error) {
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
prog := ssautil.CreateProgram(iprog, 0)
|
||||
prog := ssautil.CreateProgram(iprog, mode)
|
||||
// Set debug mode to exercise DebugRef instructions.
|
||||
prog.Package(iprog.Created[0].Pkg).SetDebugMode(true)
|
||||
prog.Build()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// go:build ignore
|
||||
|
||||
package testdata
|
||||
|
||||
func instantiated[X any](x *X) int {
|
||||
print(x)
|
||||
return 0
|
||||
}
|
||||
|
||||
type I interface {
|
||||
Bar()
|
||||
}
|
||||
|
||||
func interfaceInstantiated[X I](x X) {
|
||||
x.Bar()
|
||||
}
|
||||
|
||||
type A struct{}
|
||||
|
||||
func (a A) Bar() {}
|
||||
|
||||
type B struct{}
|
||||
|
||||
func (b B) Bar() {}
|
||||
|
||||
func Foo(a A, b B) {
|
||||
x := true
|
||||
instantiated[bool](&x)
|
||||
y := 1
|
||||
instantiated[int](&y)
|
||||
|
||||
interfaceInstantiated[A](a)
|
||||
interfaceInstantiated[B](b)
|
||||
}
|
||||
|
||||
// Relevant SSA:
|
||||
//func Foo(a A, b B):
|
||||
// t0 = local A (a)
|
||||
// *t0 = a
|
||||
// t1 = local B (b)
|
||||
// *t1 = b
|
||||
// t2 = new bool (x)
|
||||
// *t2 = true:bool
|
||||
// t3 = instantiated[[bool]](t2)
|
||||
// t4 = new int (y)
|
||||
// *t4 = 1:int
|
||||
// t5 = instantiated[[int]](t4)
|
||||
// t6 = *t0
|
||||
// t7 = interfaceInstantiated[[testdata.A]](t6)
|
||||
// t8 = *t1
|
||||
// t9 = interfaceInstantiated[[testdata.B]](t8)
|
||||
// return
|
||||
//
|
||||
//func interfaceInstantiated[[testdata.B]](x B):
|
||||
// t0 = local B (x)
|
||||
// *t0 = x
|
||||
// t1 = *t0
|
||||
// t2 = (B).Bar(t1)
|
||||
// return
|
||||
//
|
||||
//func interfaceInstantiated[X I](x X):
|
||||
// (external)
|
||||
|
||||
// WANT:
|
||||
// Foo: instantiated[[bool]](t2) -> instantiated[[bool]]; instantiated[[int]](t4) -> instantiated[[int]]; interfaceInstantiated[[testdata.A]](t6) -> interfaceInstantiated[[testdata.A]]; interfaceInstantiated[[testdata.B]](t8) -> interfaceInstantiated[[testdata.B]]
|
||||
// interfaceInstantiated[[testdata.B]]: (B).Bar(t1) -> B.Bar
|
||||
// interfaceInstantiated[[testdata.A]]: (A).Bar(t1) -> A.Bar
|
||||
|
|
@ -11,12 +11,13 @@ import (
|
|||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/callgraph/cha"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/go/ssa/ssautil"
|
||||
)
|
||||
|
||||
func TestVTACallGraphGo117(t *testing.T) {
|
||||
file := "testdata/src/go117.go"
|
||||
prog, want, err := testProg(file)
|
||||
prog, want, err := testProg(file, ssa.BuilderMode(0))
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't load test file '%s': %s", file, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"golang.org/x/tools/go/callgraph/cha"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/go/ssa/ssautil"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
func TestVTACallGraph(t *testing.T) {
|
||||
|
|
@ -27,7 +28,7 @@ func TestVTACallGraph(t *testing.T) {
|
|||
"testdata/src/callgraph_recursive_types.go",
|
||||
} {
|
||||
t.Run(file, func(t *testing.T) {
|
||||
prog, want, err := testProg(file)
|
||||
prog, want, err := testProg(file, ssa.BuilderMode(0))
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't load test file '%s': %s", file, err)
|
||||
}
|
||||
|
|
@ -47,7 +48,7 @@ func TestVTACallGraph(t *testing.T) {
|
|||
// enabled by having an arbitrary function set as input to CallGraph
|
||||
// instead of the whole program (i.e., ssautil.AllFunctions(prog)).
|
||||
func TestVTAProgVsFuncSet(t *testing.T) {
|
||||
prog, want, err := testProg("testdata/src/callgraph_nested_ptr.go")
|
||||
prog, want, err := testProg("testdata/src/callgraph_nested_ptr.go", ssa.BuilderMode(0))
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't load test `testdata/src/callgraph_nested_ptr.go`: %s", err)
|
||||
}
|
||||
|
|
@ -112,3 +113,24 @@ func TestVTAPanicMissingDefinitions(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVTACallGraphGenerics(t *testing.T) {
|
||||
if !typeparams.Enabled {
|
||||
t.Skip("TestVTACallGraphGenerics requires type parameters")
|
||||
}
|
||||
|
||||
// TODO(zpavlinovic): add more tests
|
||||
file := "testdata/src/callgraph_generics.go"
|
||||
prog, want, err := testProg(file, ssa.InstantiateGenerics)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't load test file '%s': %s", file, err)
|
||||
}
|
||||
if len(want) == 0 {
|
||||
t.Fatalf("couldn't find want in `%s`", file)
|
||||
}
|
||||
|
||||
g := CallGraph(ssautil.AllFunctions(prog), cha.CallGraph(prog))
|
||||
if got := callGraphStr(g); !subGraph(want, got) {
|
||||
t.Errorf("computed callgraph %v should contain %v", got, want)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue