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>
diff --git a/go/callgraph/vta/graph_test.go b/go/callgraph/vta/graph_test.go
index 8608844..8b8c697 100644
--- a/go/callgraph/vta/graph_test.go
+++ b/go/callgraph/vta/graph_test.go
@@ -13,6 +13,7 @@
 	"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 @@
 	//   - 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 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 @@
 		"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)
 			}
diff --git a/go/callgraph/vta/helpers_test.go b/go/callgraph/vta/helpers_test.go
index c46dd7e..768365f 100644
--- a/go/callgraph/vta/helpers_test.go
+++ b/go/callgraph/vta/helpers_test.go
@@ -35,7 +35,7 @@
 // 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 @@
 		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()
diff --git a/go/callgraph/vta/testdata/src/callgraph_generics.go b/go/callgraph/vta/testdata/src/callgraph_generics.go
new file mode 100644
index 0000000..b0fcb02
--- /dev/null
+++ b/go/callgraph/vta/testdata/src/callgraph_generics.go
@@ -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
diff --git a/go/callgraph/vta/vta_go117_test.go b/go/callgraph/vta/vta_go117_test.go
index 9ce6a88..04f6980 100644
--- a/go/callgraph/vta/vta_go117_test.go
+++ b/go/callgraph/vta/vta_go117_test.go
@@ -11,12 +11,13 @@
 	"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)
 	}
diff --git a/go/callgraph/vta/vta_test.go b/go/callgraph/vta/vta_test.go
index 8303908..4cd26a5 100644
--- a/go/callgraph/vta/vta_test.go
+++ b/go/callgraph/vta/vta_test.go
@@ -13,6 +13,7 @@
 	"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 @@
 		"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 @@
 // 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 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)
+	}
+}