merge two test cases and check possible errors

This commit is contained in:
xieyuschen 2024-09-04 11:29:25 +08:00
Родитель deda7b7b00
Коммит a859e27d81
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4C4189F4DAA5C381
3 изменённых файлов: 46 добавлений и 140 удалений

Просмотреть файл

@ -27,27 +27,52 @@ import (
"golang.org/x/tools/txtar"
)
// TestRTASingleFile runs RTA on each testdata/*.txtar file containing a single
// go file and compares the results with the expectations expressed in the WANT
// TestRTA runs RTA on each testdata/*.txtar file containing a single
// go file in a single package or multiple files in different packages,
// and compares the results with the expectations expressed in the WANT
// comment.
func TestRTASingleFile(t *testing.T) {
func TestRTA(t *testing.T) {
archivePaths := []string{
"testdata/func.txtar",
"testdata/pkgmaingenerics.txtar",
"testdata/generics.txtar",
"testdata/iface.txtar",
"testdata/reflectcall.txtar",
"testdata/rtype.txtar",
"testdata/multipkgs.txtar",
}
for _, archive := range archivePaths {
t.Run(archive, func(t *testing.T) {
pkgs := loadPackages(t, archive)
f := pkgs[0].Syntax[0]
// find the file which contains the expected result
var f *ast.File
for _, p := range pkgs {
// We assume the packages have a single file or
// the wanted result is in the first file of the main package.
if p.Name == "main" {
f = p.Syntax[0]
}
}
if f == nil {
t.Fatalf("failed to find the file with expected result within main package %s", archive)
}
prog, spkgs := ssautil.Packages(pkgs, ssa.SanityCheckFunctions|ssa.InstantiateGenerics)
// find the main package to get functions for rta analysis
var mainPkg *ssa.Package
for _, sp := range spkgs {
if sp.Pkg.Name() == "main" {
mainPkg = sp
break
}
}
if mainPkg == nil {
t.Fatalf("failed to find main ssa package %s", archive)
}
prog, spkg := ssautil.Packages(pkgs, ssa.SanityCheckFunctions|ssa.InstantiateGenerics)
prog.Build()
mainPkg := spkg[0]
res := rta.Analyze([]*ssa.Function{
mainPkg.Func("main"),
mainPkg.Func("init"),
@ -58,38 +83,6 @@ func TestRTASingleFile(t *testing.T) {
}
}
// TestRTAOnPackages runs RTA on a go module which contains multiple packages to test the case
// when an interface has implementations across different packages.
func TestRTAOnPackages(t *testing.T) {
pkgs := loadPackages(t, "testdata/multipkgs.txtar")
var f *ast.File
for _, p := range pkgs {
// We assume the packages have a single file or
// the wanted result is in the first file of the main package.
if p.Name == "main" {
f = p.Syntax[0]
}
}
prog, spkgs := ssautil.Packages(pkgs, ssa.SanityCheckFunctions|ssa.InstantiateGenerics)
prog.Build()
var mainPkg *ssa.Package
for _, sp := range spkgs {
if sp.Pkg.Name() == "main" {
mainPkg = sp
break
}
}
res := rta.Analyze([]*ssa.Function{
mainPkg.Func("main"),
mainPkg.Func("init"),
}, true)
check(t, f, mainPkg, res)
}
// loadPackages unpacks the archive to a temporary directory and loads all packages within it.
func loadPackages(t *testing.T, archive string) []*packages.Package {
ar, err := txtar.ParseFile(archive)

31
go/callgraph/rta/testdata/generics.txtar поставляемый
Просмотреть файл

@ -1,9 +1,9 @@
-- go.mod --
module example.com/generic
module example.com
go 1.18
-- generics.go --
package generic
package main
// Test of generic function calls.
@ -51,34 +51,31 @@ func lambda[X I]() func() func() {
}
}
// Note: example.com/generic is used here as we load a single file by packages.Load,
// it will use example.com/generic instead of the package name for ImportedPath
// WANT:
//
// edge (*C).Foo --static method call--> (C).Foo
// edge (A).Foo$bound --static method call--> (A).Foo
// edge instantiated[example.com/generic.A] --static method call--> (A).Foo
// edge instantiated[example.com/generic.B] --static method call--> (B).Foo
// edge instantiated[example.com.A] --static method call--> (A).Foo
// edge instantiated[example.com.B] --static method call--> (B).Foo
// edge main --dynamic method call--> (*C).Foo
// edge main --dynamic function call--> (A).Foo$bound
// edge main --dynamic method call--> (C).Foo
// edge main --static function call--> instantiated[example.com/generic.A]
// edge main --static function call--> instantiated[example.com/generic.B]
// edge main --static function call--> lambda[example.com/generic.A]
// edge main --dynamic function call--> lambda[example.com/generic.A]$1
// edge main --static function call--> local[example.com/generic.C]
// edge main --static function call--> instantiated[example.com.A]
// edge main --static function call--> instantiated[example.com.B]
// edge main --static function call--> lambda[example.com.A]
// edge main --dynamic function call--> lambda[example.com.A]$1
// edge main --static function call--> local[example.com.C]
//
// reachable (*C).Foo
// reachable (A).Foo
// reachable (A).Foo$bound
// reachable (B).Foo
// reachable (C).Foo
// reachable instantiated[example.com/generic.A]
// reachable instantiated[example.com/generic.B]
// reachable lambda[example.com/generic.A]
// reachable lambda[example.com/generic.A]$1
// reachable local[example.com/generic.C]
// reachable instantiated[example.com.A]
// reachable instantiated[example.com.B]
// reachable lambda[example.com.A]
// reachable lambda[example.com.A]$1
// reachable local[example.com.C]
//
// rtype *C
// rtype C

Просмотреть файл

@ -1,84 +0,0 @@
-- go.mod --
module example.com
go 1.18
-- generics.go --
package main
// Test of generic function calls.
type I interface {
Foo()
}
type A struct{}
func (a A) Foo() {}
type B struct{}
func (b B) Foo() {}
func instantiated[X I](x X) {
x.Foo()
}
var a A
var b B
func main() {
instantiated[A](a) // static call
instantiated[B](b) // static call
local[C]().Foo()
lambda[A]()()()
}
func local[X I]() I {
var x X
return x
}
type C struct{}
func (c C) Foo() {}
func lambda[X I]() func() func() {
return func() func() {
var x X
return x.Foo
}
}
// Note: example.com is used here as we load a single file by packages.Load,
// it will use example.com instead of the package name for ImportedPath
// WANT:
//
// edge (*C).Foo --static method call--> (C).Foo
// edge (A).Foo$bound --static method call--> (A).Foo
// edge instantiated[example.com.A] --static method call--> (A).Foo
// edge instantiated[example.com.B] --static method call--> (B).Foo
// edge main --dynamic method call--> (*C).Foo
// edge main --dynamic function call--> (A).Foo$bound
// edge main --dynamic method call--> (C).Foo
// edge main --static function call--> instantiated[example.com.A]
// edge main --static function call--> instantiated[example.com.B]
// edge main --static function call--> lambda[example.com.A]
// edge main --dynamic function call--> lambda[example.com.A]$1
// edge main --static function call--> local[example.com.C]
//
// reachable (*C).Foo
// reachable (A).Foo
// reachable (A).Foo$bound
// reachable (B).Foo
// reachable (C).Foo
// reachable instantiated[example.com.A]
// reachable instantiated[example.com.B]
// reachable lambda[example.com.A]
// reachable lambda[example.com.A]$1
// reachable local[example.com.C]
//
// rtype *C
// rtype C