diff options
Diffstat (limited to 'go/ssa/ssautil/load_test.go')
-rw-r--r-- | go/ssa/ssautil/load_test.go | 120 |
1 files changed, 95 insertions, 25 deletions
diff --git a/go/ssa/ssautil/load_test.go b/go/ssa/ssautil/load_test.go index 55684e0a6..efa2ba40a 100644 --- a/go/ssa/ssautil/load_test.go +++ b/go/ssa/ssautil/load_test.go @@ -12,10 +12,13 @@ import ( "go/token" "go/types" "os" + "path" "strings" "testing" "golang.org/x/tools/go/packages" + "golang.org/x/tools/go/packages/packagestest" + "golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa/ssautil" "golang.org/x/tools/internal/testenv" ) @@ -30,6 +33,8 @@ func main() { ` func TestBuildPackage(t *testing.T) { + testenv.NeedsGoBuild(t) // for importer.Default() + // There is a more substantial test of BuildPackage and the // SSA program it builds in ../ssa/builder_test.go. @@ -39,17 +44,23 @@ func TestBuildPackage(t *testing.T) { t.Fatal(err) } - pkg := types.NewPackage("hello", "") - ssapkg, _, err := ssautil.BuildPackage(&types.Config{Importer: importer.Default()}, fset, pkg, []*ast.File{f}, 0) - if err != nil { - t.Fatal(err) - } - if pkg.Name() != "main" { - t.Errorf("pkg.Name() = %s, want main", pkg.Name()) - } - if ssapkg.Func("main") == nil { - ssapkg.WriteTo(os.Stderr) - t.Errorf("ssapkg has no main function") + for _, mode := range []ssa.BuilderMode{ + ssa.SanityCheckFunctions, + ssa.InstantiateGenerics | ssa.SanityCheckFunctions, + } { + pkg := types.NewPackage("hello", "") + ssapkg, _, err := ssautil.BuildPackage(&types.Config{Importer: importer.Default()}, fset, pkg, []*ast.File{f}, mode) + if err != nil { + t.Fatal(err) + } + if pkg.Name() != "main" { + t.Errorf("pkg.Name() = %s, want main", pkg.Name()) + } + if ssapkg.Func("main") == nil { + ssapkg.WriteTo(os.Stderr) + t.Errorf("ssapkg has no main function") + } + } } @@ -65,19 +76,23 @@ func TestPackages(t *testing.T) { t.Fatal("there were errors") } - prog, pkgs := ssautil.Packages(initial, 0) - bytesNewBuffer := pkgs[0].Func("NewBuffer") - bytesNewBuffer.Pkg.Build() + for _, mode := range []ssa.BuilderMode{ + ssa.SanityCheckFunctions, + ssa.SanityCheckFunctions | ssa.InstantiateGenerics, + } { + prog, pkgs := ssautil.Packages(initial, mode) + bytesNewBuffer := pkgs[0].Func("NewBuffer") + bytesNewBuffer.Pkg.Build() - // We'll dump the SSA of bytes.NewBuffer because it is small and stable. - out := new(bytes.Buffer) - bytesNewBuffer.WriteTo(out) + // We'll dump the SSA of bytes.NewBuffer because it is small and stable. + out := new(bytes.Buffer) + bytesNewBuffer.WriteTo(out) - // For determinism, sanitize the location. - location := prog.Fset.Position(bytesNewBuffer.Pos()).String() - got := strings.Replace(out.String(), location, "$GOROOT/src/bytes/buffer.go:1", -1) + // For determinism, sanitize the location. + location := prog.Fset.Position(bytesNewBuffer.Pos()).String() + got := strings.Replace(out.String(), location, "$GOROOT/src/bytes/buffer.go:1", -1) - want := ` + want := ` # Name: bytes.NewBuffer # Package: bytes # Location: $GOROOT/src/bytes/buffer.go:1 @@ -89,8 +104,9 @@ func NewBuffer(buf []byte) *Buffer: return t0 `[1:] - if got != want { - t.Errorf("bytes.NewBuffer SSA = <<%s>>, want <<%s>>", got, want) + if got != want { + t.Errorf("bytes.NewBuffer SSA = <<%s>>, want <<%s>>", got, want) + } } } @@ -102,7 +118,7 @@ func TestBuildPackage_MissingImport(t *testing.T) { } pkg := types.NewPackage("bad", "") - ssapkg, _, err := ssautil.BuildPackage(new(types.Config), fset, pkg, []*ast.File{f}, 0) + ssapkg, _, err := ssautil.BuildPackage(new(types.Config), fset, pkg, []*ast.File{f}, ssa.BuilderMode(0)) if err == nil || ssapkg != nil { t.Fatal("BuildPackage succeeded unexpectedly") } @@ -120,6 +136,60 @@ func TestIssue28106(t *testing.T) { if err != nil { t.Fatal(err) } - prog, _ := ssautil.Packages(pkgs, 0) + prog, _ := ssautil.Packages(pkgs, ssa.BuilderMode(0)) prog.Build() // no crash } + +func TestIssue53604(t *testing.T) { + // Tests that variable initializers are not added to init() when syntax + // is not present but types.Info is available. + // + // Packages x, y, z are loaded with mode `packages.LoadSyntax`. + // Package x imports y, and y imports z. + // Packages are built using ssautil.Packages() with x and z as roots. + // This setup creates y using CreatePackage(pkg, files, info, ...) + // where len(files) == 0 but info != nil. + // + // Tests that globals from y are not initialized. + e := packagestest.Export(t, packagestest.Modules, []packagestest.Module{ + { + Name: "golang.org/fake", + Files: map[string]interface{}{ + "x/x.go": `package x; import "golang.org/fake/y"; var V = y.F()`, + "y/y.go": `package y; import "golang.org/fake/z"; var F = func () *int { return &z.Z } `, + "z/z.go": `package z; var Z int`, + }, + }, + }) + defer e.Cleanup() + + // Load x and z as entry packages using packages.LoadSyntax + e.Config.Mode = packages.LoadSyntax + pkgs, err := packages.Load(e.Config, path.Join(e.Temp(), "fake/x"), path.Join(e.Temp(), "fake/z")) + if err != nil { + t.Fatal(err) + } + for _, p := range pkgs { + if len(p.Errors) > 0 { + t.Fatalf("%v", p.Errors) + } + } + + prog, _ := ssautil.Packages(pkgs, ssa.BuilderMode(0)) + prog.Build() + + // y does not initialize F. + y := prog.ImportedPackage("golang.org/fake/y") + if y == nil { + t.Fatal("Failed to load intermediate package y") + } + yinit := y.Members["init"].(*ssa.Function) + for _, bb := range yinit.Blocks { + for _, i := range bb.Instrs { + if store, ok := i.(*ssa.Store); ok && store.Addr == y.Var("F") { + t.Errorf("y.init() stores to F %v", store) + } + } + } + +} |