golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/go/ssa/ssautil/load_test.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ssautil_test 6 7 import ( 8 "bytes" 9 "go/ast" 10 "go/importer" 11 "go/parser" 12 "go/token" 13 "go/types" 14 "os" 15 "path" 16 "strings" 17 "testing" 18 19 "golang.org/x/tools/go/packages" 20 "golang.org/x/tools/go/packages/packagestest" 21 "golang.org/x/tools/go/ssa" 22 "golang.org/x/tools/go/ssa/ssautil" 23 "golang.org/x/tools/internal/testenv" 24 ) 25 26 const hello = `package main 27 28 import "fmt" 29 30 func main() { 31 fmt.Println("Hello, world") 32 } 33 ` 34 35 func TestBuildPackage(t *testing.T) { 36 testenv.NeedsGoBuild(t) // for importer.Default() 37 38 // There is a more substantial test of BuildPackage and the 39 // SSA program it builds in ../ssa/builder_test.go. 40 41 fset := token.NewFileSet() 42 f, err := parser.ParseFile(fset, "hello.go", hello, 0) 43 if err != nil { 44 t.Fatal(err) 45 } 46 47 for _, mode := range []ssa.BuilderMode{ 48 ssa.SanityCheckFunctions, 49 ssa.InstantiateGenerics | ssa.SanityCheckFunctions, 50 } { 51 pkg := types.NewPackage("hello", "") 52 ssapkg, _, err := ssautil.BuildPackage(&types.Config{Importer: importer.Default()}, fset, pkg, []*ast.File{f}, mode) 53 if err != nil { 54 t.Fatal(err) 55 } 56 if pkg.Name() != "main" { 57 t.Errorf("pkg.Name() = %s, want main", pkg.Name()) 58 } 59 if ssapkg.Func("main") == nil { 60 ssapkg.WriteTo(os.Stderr) 61 t.Errorf("ssapkg has no main function") 62 } 63 64 } 65 } 66 67 func TestPackages(t *testing.T) { 68 testenv.NeedsGoPackages(t) 69 70 cfg := &packages.Config{Mode: packages.LoadSyntax} 71 initial, err := packages.Load(cfg, "bytes") 72 if err != nil { 73 t.Fatal(err) 74 } 75 if packages.PrintErrors(initial) > 0 { 76 t.Fatal("there were errors") 77 } 78 79 for _, mode := range []ssa.BuilderMode{ 80 ssa.SanityCheckFunctions, 81 ssa.SanityCheckFunctions | ssa.InstantiateGenerics, 82 } { 83 prog, pkgs := ssautil.Packages(initial, mode) 84 bytesNewBuffer := pkgs[0].Func("NewBuffer") 85 bytesNewBuffer.Pkg.Build() 86 87 // We'll dump the SSA of bytes.NewBuffer because it is small and stable. 88 out := new(bytes.Buffer) 89 bytesNewBuffer.WriteTo(out) 90 91 // For determinism, sanitize the location. 92 location := prog.Fset.Position(bytesNewBuffer.Pos()).String() 93 got := strings.Replace(out.String(), location, "$GOROOT/src/bytes/buffer.go:1", -1) 94 95 want := ` 96 # Name: bytes.NewBuffer 97 # Package: bytes 98 # Location: $GOROOT/src/bytes/buffer.go:1 99 func NewBuffer(buf []byte) *Buffer: 100 0: entry P:0 S:0 101 t0 = new Buffer (complit) *Buffer 102 t1 = &t0.buf [#0] *[]byte 103 *t1 = buf 104 return t0 105 106 `[1:] 107 if got != want { 108 t.Errorf("bytes.NewBuffer SSA = <<%s>>, want <<%s>>", got, want) 109 } 110 } 111 } 112 113 func TestBuildPackage_MissingImport(t *testing.T) { 114 fset := token.NewFileSet() 115 f, err := parser.ParseFile(fset, "bad.go", `package bad; import "missing"`, 0) 116 if err != nil { 117 t.Fatal(err) 118 } 119 120 pkg := types.NewPackage("bad", "") 121 ssapkg, _, err := ssautil.BuildPackage(new(types.Config), fset, pkg, []*ast.File{f}, ssa.BuilderMode(0)) 122 if err == nil || ssapkg != nil { 123 t.Fatal("BuildPackage succeeded unexpectedly") 124 } 125 } 126 127 func TestIssue28106(t *testing.T) { 128 testenv.NeedsGoPackages(t) 129 130 // In go1.10, go/packages loads all packages from source, not 131 // export data, but does not type check function bodies of 132 // imported packages. This test ensures that we do not attempt 133 // to run the SSA builder on functions without type information. 134 cfg := &packages.Config{Mode: packages.LoadSyntax} 135 pkgs, err := packages.Load(cfg, "runtime") 136 if err != nil { 137 t.Fatal(err) 138 } 139 prog, _ := ssautil.Packages(pkgs, ssa.BuilderMode(0)) 140 prog.Build() // no crash 141 } 142 143 func TestIssue53604(t *testing.T) { 144 // Tests that variable initializers are not added to init() when syntax 145 // is not present but types.Info is available. 146 // 147 // Packages x, y, z are loaded with mode `packages.LoadSyntax`. 148 // Package x imports y, and y imports z. 149 // Packages are built using ssautil.Packages() with x and z as roots. 150 // This setup creates y using CreatePackage(pkg, files, info, ...) 151 // where len(files) == 0 but info != nil. 152 // 153 // Tests that globals from y are not initialized. 154 e := packagestest.Export(t, packagestest.Modules, []packagestest.Module{ 155 { 156 Name: "golang.org/fake", 157 Files: map[string]interface{}{ 158 "x/x.go": `package x; import "golang.org/fake/y"; var V = y.F()`, 159 "y/y.go": `package y; import "golang.org/fake/z"; var F = func () *int { return &z.Z } `, 160 "z/z.go": `package z; var Z int`, 161 }, 162 }, 163 }) 164 defer e.Cleanup() 165 166 // Load x and z as entry packages using packages.LoadSyntax 167 e.Config.Mode = packages.LoadSyntax 168 pkgs, err := packages.Load(e.Config, path.Join(e.Temp(), "fake/x"), path.Join(e.Temp(), "fake/z")) 169 if err != nil { 170 t.Fatal(err) 171 } 172 for _, p := range pkgs { 173 if len(p.Errors) > 0 { 174 t.Fatalf("%v", p.Errors) 175 } 176 } 177 178 prog, _ := ssautil.Packages(pkgs, ssa.BuilderMode(0)) 179 prog.Build() 180 181 // y does not initialize F. 182 y := prog.ImportedPackage("golang.org/fake/y") 183 if y == nil { 184 t.Fatal("Failed to load intermediate package y") 185 } 186 yinit := y.Members["init"].(*ssa.Function) 187 for _, bb := range yinit.Blocks { 188 for _, i := range bb.Instrs { 189 if store, ok := i.(*ssa.Store); ok && store.Addr == y.Var("F") { 190 t.Errorf("y.init() stores to F %v", store) 191 } 192 } 193 } 194 195 }