go/callgraph/static: adds tests for (instantiated) generics
Updates golang/go#48525
Change-Id: If460999912fecad626ec8cbace251dd6a0358196
Reviewed-on: https://go-review.googlesource.com/c/tools/+/402695
Reviewed-by: Tim King <taking@google.com>
Reviewed-by: Alan Donovan <alan@alandonovan.net>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Zvonimir Pavlinovic <zpavlinovic@google.com>
diff --git a/go/callgraph/static/static_test.go b/go/callgraph/static/static_test.go
index e1bfcd7..47f32d7 100644
--- a/go/callgraph/static/static_test.go
+++ b/go/callgraph/static/static_test.go
@@ -14,7 +14,9 @@
"golang.org/x/tools/go/callgraph"
"golang.org/x/tools/go/callgraph/static"
"golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/internal/typeparams"
)
const input = `package P
@@ -47,42 +49,94 @@
var unknown bool
`
+const genericsInput = `package P
+
+type I interface {
+ F()
+}
+
+type A struct{}
+
+func (a A) F() {}
+
+type B struct{}
+
+func (b B) F() {}
+
+func instantiated[X I](x X) {
+ x.F()
+}
+
+func Bar() {}
+
+func f(h func(), a A, b B) {
+ h()
+
+ instantiated[A](a)
+ instantiated[B](b)
+}
+`
+
func TestStatic(t *testing.T) {
- conf := loader.Config{ParserMode: parser.ParseComments}
- f, err := conf.ParseFile("P.go", input)
- if err != nil {
- t.Fatal(err)
- }
+ for _, e := range []struct {
+ input string
+ want []string
+ // typeparams must be true if input uses type parameters
+ typeparams bool
+ }{
+ {input, []string{
+ "(*C).f -> (C).f",
+ "f -> (C).f",
+ "f -> f$1",
+ "f -> g",
+ }, false},
+ {genericsInput, []string{
+ "(*A).F -> (A).F",
+ "(*B).F -> (B).F",
+ "f -> instantiated[[P.A]]",
+ "f -> instantiated[[P.B]]",
+ "instantiated[[P.A]] -> (A).F",
+ "instantiated[[P.B]] -> (B).F",
+ }, true},
+ } {
+ if e.typeparams && !typeparams.Enabled {
+ // Skip tests with type parameters when the build
+ // environment is not supporting any.
+ continue
+ }
- conf.CreateFromFiles("P", f)
- iprog, err := conf.Load()
- if err != nil {
- t.Fatal(err)
- }
+ conf := loader.Config{ParserMode: parser.ParseComments}
+ f, err := conf.ParseFile("P.go", e.input)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
- P := iprog.Created[0].Pkg
+ conf.CreateFromFiles("P", f)
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Error(err)
+ continue
+ }
- prog := ssautil.CreateProgram(iprog, 0)
- prog.Build()
+ P := iprog.Created[0].Pkg
- cg := static.CallGraph(prog)
+ prog := ssautil.CreateProgram(iprog, ssa.InstantiateGenerics)
+ prog.Build()
- var edges []string
- callgraph.GraphVisitEdges(cg, func(e *callgraph.Edge) error {
- edges = append(edges, fmt.Sprintf("%s -> %s",
- e.Caller.Func.RelString(P),
- e.Callee.Func.RelString(P)))
- return nil
- })
- sort.Strings(edges)
+ cg := static.CallGraph(prog)
- want := []string{
- "(*C).f -> (C).f",
- "f -> (C).f",
- "f -> f$1",
- "f -> g",
- }
- if !reflect.DeepEqual(edges, want) {
- t.Errorf("Got edges %v, want %v", edges, want)
+ var edges []string
+ callgraph.GraphVisitEdges(cg, func(e *callgraph.Edge) error {
+ edges = append(edges, fmt.Sprintf("%s -> %s",
+ e.Caller.Func.RelString(P),
+ e.Callee.Func.RelString(P)))
+ return nil
+ })
+ sort.Strings(edges)
+
+ if !reflect.DeepEqual(edges, e.want) {
+ t.Errorf("Got edges %v, want %v", edges, e.want)
+ }
}
}