...

Source file src/golang.org/x/tools/go/ssa/ssautil/load_test.go

Documentation: golang.org/x/tools/go/ssa/ssautil

     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  }
   196  

View as plain text