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>
This commit is contained in:
Zvonimir Pavlinovic 2022-04-27 14:17:19 -07:00
parent a37ba1418f
commit 60b4456604
1 changed files with 84 additions and 30 deletions

View File

@ -14,7 +14,9 @@ import (
"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 @@ func h()
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)
}
}
}