Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/importer/gcimporter_test.go

Documentation: cmd/compile/internal/importer

     1  // UNREVIEWED
     2  // Copyright 2011 The Go Authors. All rights reserved.
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package importer
     7  
     8  import (
     9  	"bytes"
    10  	"cmd/compile/internal/types2"
    11  	"fmt"
    12  	"internal/testenv"
    13  	"io/ioutil"
    14  	"os"
    15  	"os/exec"
    16  	"path/filepath"
    17  	"runtime"
    18  	"strings"
    19  	"testing"
    20  	"time"
    21  )
    22  
    23  // skipSpecialPlatforms causes the test to be skipped for platforms where
    24  // builders (build.golang.org) don't have access to compiled packages for
    25  // import.
    26  func skipSpecialPlatforms(t *testing.T) {
    27  	switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform {
    28  	case "darwin-arm64":
    29  		t.Skipf("no compiled packages available for import on %s", platform)
    30  	}
    31  }
    32  
    33  // compile runs the compiler on filename, with dirname as the working directory,
    34  // and writes the output file to outdirname.
    35  func compile(t *testing.T, dirname, filename, outdirname string) string {
    36  	// filename must end with ".go"
    37  	if !strings.HasSuffix(filename, ".go") {
    38  		t.Fatalf("filename doesn't end in .go: %s", filename)
    39  	}
    40  	basename := filepath.Base(filename)
    41  	outname := filepath.Join(outdirname, basename[:len(basename)-2]+"o")
    42  	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", outname, filename)
    43  	cmd.Dir = dirname
    44  	out, err := cmd.CombinedOutput()
    45  	if err != nil {
    46  		t.Logf("%s", out)
    47  		t.Fatalf("go tool compile %s failed: %s", filename, err)
    48  	}
    49  	return outname
    50  }
    51  
    52  func testPath(t *testing.T, path, srcDir string) *types2.Package {
    53  	t0 := time.Now()
    54  	pkg, err := Import(make(map[string]*types2.Package), path, srcDir, nil)
    55  	if err != nil {
    56  		t.Errorf("testPath(%s): %s", path, err)
    57  		return nil
    58  	}
    59  	t.Logf("testPath(%s): %v", path, time.Since(t0))
    60  	return pkg
    61  }
    62  
    63  const maxTime = 30 * time.Second
    64  
    65  func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
    66  	dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
    67  	list, err := ioutil.ReadDir(dirname)
    68  	if err != nil {
    69  		t.Fatalf("testDir(%s): %s", dirname, err)
    70  	}
    71  	for _, f := range list {
    72  		if time.Now().After(endTime) {
    73  			t.Log("testing time used up")
    74  			return
    75  		}
    76  		switch {
    77  		case !f.IsDir():
    78  			// try extensions
    79  			for _, ext := range pkgExts {
    80  				if strings.HasSuffix(f.Name(), ext) {
    81  					name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension
    82  					if testPath(t, filepath.Join(dir, name), dir) != nil {
    83  						nimports++
    84  					}
    85  				}
    86  			}
    87  		case f.IsDir():
    88  			nimports += testDir(t, filepath.Join(dir, f.Name()), endTime)
    89  		}
    90  	}
    91  	return
    92  }
    93  
    94  func mktmpdir(t *testing.T) string {
    95  	tmpdir, err := ioutil.TempDir("", "gcimporter_test")
    96  	if err != nil {
    97  		t.Fatal("mktmpdir:", err)
    98  	}
    99  	if err := os.Mkdir(filepath.Join(tmpdir, "testdata"), 0700); err != nil {
   100  		os.RemoveAll(tmpdir)
   101  		t.Fatal("mktmpdir:", err)
   102  	}
   103  	return tmpdir
   104  }
   105  
   106  func TestImportTestdata(t *testing.T) {
   107  	// This package only handles gc export data.
   108  	if runtime.Compiler != "gc" {
   109  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   110  	}
   111  
   112  	tmpdir := mktmpdir(t)
   113  	defer os.RemoveAll(tmpdir)
   114  
   115  	compile(t, "testdata", "exports.go", filepath.Join(tmpdir, "testdata"))
   116  
   117  	if pkg := testPath(t, "./testdata/exports", tmpdir); pkg != nil {
   118  		// The package's Imports list must include all packages
   119  		// explicitly imported by exports.go, plus all packages
   120  		// referenced indirectly via exported objects in exports.go.
   121  		// With the textual export format, the list may also include
   122  		// additional packages that are not strictly required for
   123  		// import processing alone (they are exported to err "on
   124  		// the safe side").
   125  		// TODO(gri) update the want list to be precise, now that
   126  		// the textual export data is gone.
   127  		got := fmt.Sprint(pkg.Imports())
   128  		for _, want := range []string{"go/ast", "go/token"} {
   129  			if !strings.Contains(got, want) {
   130  				t.Errorf(`Package("exports").Imports() = %s, does not contain %s`, got, want)
   131  			}
   132  		}
   133  	}
   134  }
   135  
   136  func TestVersionHandling(t *testing.T) {
   137  	skipSpecialPlatforms(t)
   138  
   139  	// This package only handles gc export data.
   140  	if runtime.Compiler != "gc" {
   141  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   142  	}
   143  
   144  	const dir = "./testdata/versions"
   145  	list, err := ioutil.ReadDir(dir)
   146  	if err != nil {
   147  		t.Fatal(err)
   148  	}
   149  
   150  	tmpdir := mktmpdir(t)
   151  	defer os.RemoveAll(tmpdir)
   152  	corruptdir := filepath.Join(tmpdir, "testdata", "versions")
   153  	if err := os.Mkdir(corruptdir, 0700); err != nil {
   154  		t.Fatal(err)
   155  	}
   156  
   157  	for _, f := range list {
   158  		name := f.Name()
   159  		if !strings.HasSuffix(name, ".a") {
   160  			continue // not a package file
   161  		}
   162  		if strings.Contains(name, "corrupted") {
   163  			continue // don't process a leftover corrupted file
   164  		}
   165  		pkgpath := "./" + name[:len(name)-2]
   166  
   167  		if testing.Verbose() {
   168  			t.Logf("importing %s", name)
   169  		}
   170  
   171  		// test that export data can be imported
   172  		_, err := Import(make(map[string]*types2.Package), pkgpath, dir, nil)
   173  		if err != nil {
   174  			// ok to fail if it fails with a no longer supported error for select files
   175  			if strings.Contains(err.Error(), "no longer supported") {
   176  				switch name {
   177  				case "test_go1.7_0.a", "test_go1.7_1.a",
   178  					"test_go1.8_4.a", "test_go1.8_5.a",
   179  					"test_go1.11_6b.a", "test_go1.11_999b.a":
   180  					continue
   181  				}
   182  				// fall through
   183  			}
   184  			// ok to fail if it fails with a newer version error for select files
   185  			if strings.Contains(err.Error(), "newer version") {
   186  				switch name {
   187  				case "test_go1.11_999i.a":
   188  					continue
   189  				}
   190  				// fall through
   191  			}
   192  			t.Errorf("import %q failed: %v", pkgpath, err)
   193  			continue
   194  		}
   195  
   196  		// create file with corrupted export data
   197  		// 1) read file
   198  		data, err := ioutil.ReadFile(filepath.Join(dir, name))
   199  		if err != nil {
   200  			t.Fatal(err)
   201  		}
   202  		// 2) find export data
   203  		i := bytes.Index(data, []byte("\n$$B\n")) + 5
   204  		j := bytes.Index(data[i:], []byte("\n$$\n")) + i
   205  		if i < 0 || j < 0 || i > j {
   206  			t.Fatalf("export data section not found (i = %d, j = %d)", i, j)
   207  		}
   208  		// 3) corrupt the data (increment every 7th byte)
   209  		for k := j - 13; k >= i; k -= 7 {
   210  			data[k]++
   211  		}
   212  		// 4) write the file
   213  		pkgpath += "_corrupted"
   214  		filename := filepath.Join(corruptdir, pkgpath) + ".a"
   215  		ioutil.WriteFile(filename, data, 0666)
   216  
   217  		// test that importing the corrupted file results in an error
   218  		_, err = Import(make(map[string]*types2.Package), pkgpath, corruptdir, nil)
   219  		if err == nil {
   220  			t.Errorf("import corrupted %q succeeded", pkgpath)
   221  		} else if msg := err.Error(); !strings.Contains(msg, "version skew") {
   222  			t.Errorf("import %q error incorrect (%s)", pkgpath, msg)
   223  		}
   224  	}
   225  }
   226  
   227  func TestImportStdLib(t *testing.T) {
   228  	skipSpecialPlatforms(t)
   229  
   230  	// This package only handles gc export data.
   231  	if runtime.Compiler != "gc" {
   232  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   233  	}
   234  
   235  	dt := maxTime
   236  	if testing.Short() && testenv.Builder() == "" {
   237  		dt = 10 * time.Millisecond
   238  	}
   239  	nimports := testDir(t, "", time.Now().Add(dt)) // installed packages
   240  	t.Logf("tested %d imports", nimports)
   241  }
   242  
   243  var importedObjectTests = []struct {
   244  	name string
   245  	want string
   246  }{
   247  	// non-interfaces
   248  	{"crypto.Hash", "type Hash uint"},
   249  	{"go/ast.ObjKind", "type ObjKind int"},
   250  	{"go/types.Qualifier", "type Qualifier func(*Package) string"},
   251  	{"go/types.Comparable", "func Comparable(T Type) bool"},
   252  	{"math.Pi", "const Pi untyped float"},
   253  	{"math.Sin", "func Sin(x float64) float64"},
   254  	{"go/ast.NotNilFilter", "func NotNilFilter(_ string, v reflect.Value) bool"},
   255  	{"go/internal/gcimporter.FindPkg", "func FindPkg(path string, srcDir string) (filename string, id string)"},
   256  
   257  	// interfaces
   258  	{"context.Context", "type Context interface{Deadline() (deadline time.Time, ok bool); Done() <-chan struct{}; Err() error; Value(key interface{}) interface{}}"},
   259  	{"crypto.Decrypter", "type Decrypter interface{Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error); Public() PublicKey}"},
   260  	{"encoding.BinaryMarshaler", "type BinaryMarshaler interface{MarshalBinary() (data []byte, err error)}"},
   261  	{"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
   262  	{"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"},
   263  	{"go/ast.Node", "type Node interface{End() go/token.Pos; Pos() go/token.Pos}"},
   264  	// go/types.Type has grown much larger - excluded for now
   265  	// {"go/types.Type", "type Type interface{String() string; Underlying() Type}"},
   266  }
   267  
   268  func TestImportedTypes(t *testing.T) {
   269  	skipSpecialPlatforms(t)
   270  
   271  	// This package only handles gc export data.
   272  	if runtime.Compiler != "gc" {
   273  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   274  	}
   275  
   276  	for _, test := range importedObjectTests {
   277  		s := strings.Split(test.name, ".")
   278  		if len(s) != 2 {
   279  			t.Fatal("inconsistent test data")
   280  		}
   281  		importPath := s[0]
   282  		objName := s[1]
   283  
   284  		pkg, err := Import(make(map[string]*types2.Package), importPath, ".", nil)
   285  		if err != nil {
   286  			t.Error(err)
   287  			continue
   288  		}
   289  
   290  		obj := pkg.Scope().Lookup(objName)
   291  		if obj == nil {
   292  			t.Errorf("%s: object not found", test.name)
   293  			continue
   294  		}
   295  
   296  		got := types2.ObjectString(obj, types2.RelativeTo(pkg))
   297  		if got != test.want {
   298  			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
   299  		}
   300  
   301  		if named, _ := obj.Type().(*types2.Named); named != nil {
   302  			verifyInterfaceMethodRecvs(t, named, 0)
   303  		}
   304  	}
   305  }
   306  
   307  // verifyInterfaceMethodRecvs verifies that method receiver types
   308  // are named if the methods belong to a named interface type.
   309  func verifyInterfaceMethodRecvs(t *testing.T, named *types2.Named, level int) {
   310  	// avoid endless recursion in case of an embedding bug that lead to a cycle
   311  	if level > 10 {
   312  		t.Errorf("%s: embeds itself", named)
   313  		return
   314  	}
   315  
   316  	iface, _ := named.Underlying().(*types2.Interface)
   317  	if iface == nil {
   318  		return // not an interface
   319  	}
   320  
   321  	// check explicitly declared methods
   322  	for i := 0; i < iface.NumExplicitMethods(); i++ {
   323  		m := iface.ExplicitMethod(i)
   324  		recv := m.Type().(*types2.Signature).Recv()
   325  		if recv == nil {
   326  			t.Errorf("%s: missing receiver type", m)
   327  			continue
   328  		}
   329  		if recv.Type() != named {
   330  			t.Errorf("%s: got recv type %s; want %s", m, recv.Type(), named)
   331  		}
   332  	}
   333  
   334  	// check embedded interfaces (if they are named, too)
   335  	for i := 0; i < iface.NumEmbeddeds(); i++ {
   336  		// embedding of interfaces cannot have cycles; recursion will terminate
   337  		if etype, _ := iface.EmbeddedType(i).(*types2.Named); etype != nil {
   338  			verifyInterfaceMethodRecvs(t, etype, level+1)
   339  		}
   340  	}
   341  }
   342  
   343  func TestIssue5815(t *testing.T) {
   344  	skipSpecialPlatforms(t)
   345  
   346  	// This package only handles gc export data.
   347  	if runtime.Compiler != "gc" {
   348  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   349  	}
   350  
   351  	pkg := importPkg(t, "strings", ".")
   352  
   353  	scope := pkg.Scope()
   354  	for _, name := range scope.Names() {
   355  		obj := scope.Lookup(name)
   356  		if obj.Pkg() == nil {
   357  			t.Errorf("no pkg for %s", obj)
   358  		}
   359  		if tname, _ := obj.(*types2.TypeName); tname != nil {
   360  			named := tname.Type().(*types2.Named)
   361  			for i := 0; i < named.NumMethods(); i++ {
   362  				m := named.Method(i)
   363  				if m.Pkg() == nil {
   364  					t.Errorf("no pkg for %s", m)
   365  				}
   366  			}
   367  		}
   368  	}
   369  }
   370  
   371  // Smoke test to ensure that imported methods get the correct package.
   372  func TestCorrectMethodPackage(t *testing.T) {
   373  	skipSpecialPlatforms(t)
   374  
   375  	// This package only handles gc export data.
   376  	if runtime.Compiler != "gc" {
   377  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   378  	}
   379  
   380  	imports := make(map[string]*types2.Package)
   381  	_, err := Import(imports, "net/http", ".", nil)
   382  	if err != nil {
   383  		t.Fatal(err)
   384  	}
   385  
   386  	mutex := imports["sync"].Scope().Lookup("Mutex").(*types2.TypeName).Type()
   387  	obj, _, _ := types2.LookupFieldOrMethod(types2.NewPointer(mutex), false, nil, "Lock")
   388  	lock := obj.(*types2.Func)
   389  	if got, want := lock.Pkg().Path(), "sync"; got != want {
   390  		t.Errorf("got package path %q; want %q", got, want)
   391  	}
   392  }
   393  
   394  func TestIssue13566(t *testing.T) {
   395  	skipSpecialPlatforms(t)
   396  
   397  	// This package only handles gc export data.
   398  	if runtime.Compiler != "gc" {
   399  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   400  	}
   401  
   402  	// On windows, we have to set the -D option for the compiler to avoid having a drive
   403  	// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
   404  	if runtime.GOOS == "windows" {
   405  		t.Skip("avoid dealing with relative paths/drive letters on windows")
   406  	}
   407  
   408  	tmpdir := mktmpdir(t)
   409  	defer os.RemoveAll(tmpdir)
   410  	testoutdir := filepath.Join(tmpdir, "testdata")
   411  
   412  	// b.go needs to be compiled from the output directory so that the compiler can
   413  	// find the compiled package a. We pass the full path to compile() so that we
   414  	// don't have to copy the file to that directory.
   415  	bpath, err := filepath.Abs(filepath.Join("testdata", "b.go"))
   416  	if err != nil {
   417  		t.Fatal(err)
   418  	}
   419  	compile(t, "testdata", "a.go", testoutdir)
   420  	compile(t, testoutdir, bpath, testoutdir)
   421  
   422  	// import must succeed (test for issue at hand)
   423  	pkg := importPkg(t, "./testdata/b", tmpdir)
   424  
   425  	// make sure all indirectly imported packages have names
   426  	for _, imp := range pkg.Imports() {
   427  		if imp.Name() == "" {
   428  			t.Errorf("no name for %s package", imp.Path())
   429  		}
   430  	}
   431  }
   432  
   433  func TestIssue13898(t *testing.T) {
   434  	skipSpecialPlatforms(t)
   435  
   436  	// This package only handles gc export data.
   437  	if runtime.Compiler != "gc" {
   438  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   439  	}
   440  
   441  	// import go/internal/gcimporter which imports go/types partially
   442  	imports := make(map[string]*types2.Package)
   443  	_, err := Import(imports, "go/internal/gcimporter", ".", nil)
   444  	if err != nil {
   445  		t.Fatal(err)
   446  	}
   447  
   448  	// look for go/types package
   449  	var goTypesPkg *types2.Package
   450  	for path, pkg := range imports {
   451  		if path == "go/types" {
   452  			goTypesPkg = pkg
   453  			break
   454  		}
   455  	}
   456  	if goTypesPkg == nil {
   457  		t.Fatal("go/types not found")
   458  	}
   459  
   460  	// look for go/types2.Object type
   461  	obj := lookupObj(t, goTypesPkg.Scope(), "Object")
   462  	typ, ok := obj.Type().(*types2.Named)
   463  	if !ok {
   464  		t.Fatalf("go/types2.Object type is %v; wanted named type", typ)
   465  	}
   466  
   467  	// lookup go/types2.Object.Pkg method
   468  	m, index, indirect := types2.LookupFieldOrMethod(typ, false, nil, "Pkg")
   469  	if m == nil {
   470  		t.Fatalf("go/types2.Object.Pkg not found (index = %v, indirect = %v)", index, indirect)
   471  	}
   472  
   473  	// the method must belong to go/types
   474  	if m.Pkg().Path() != "go/types" {
   475  		t.Fatalf("found %v; want go/types", m.Pkg())
   476  	}
   477  }
   478  
   479  func TestIssue15517(t *testing.T) {
   480  	skipSpecialPlatforms(t)
   481  
   482  	// This package only handles gc export data.
   483  	if runtime.Compiler != "gc" {
   484  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   485  	}
   486  
   487  	// On windows, we have to set the -D option for the compiler to avoid having a drive
   488  	// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
   489  	if runtime.GOOS == "windows" {
   490  		t.Skip("avoid dealing with relative paths/drive letters on windows")
   491  	}
   492  
   493  	tmpdir := mktmpdir(t)
   494  	defer os.RemoveAll(tmpdir)
   495  
   496  	compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"))
   497  
   498  	// Multiple imports of p must succeed without redeclaration errors.
   499  	// We use an import path that's not cleaned up so that the eventual
   500  	// file path for the package is different from the package path; this
   501  	// will expose the error if it is present.
   502  	//
   503  	// (Issue: Both the textual and the binary importer used the file path
   504  	// of the package to be imported as key into the shared packages map.
   505  	// However, the binary importer then used the package path to identify
   506  	// the imported package to mark it as complete; effectively marking the
   507  	// wrong package as complete. By using an "unclean" package path, the
   508  	// file and package path are different, exposing the problem if present.
   509  	// The same issue occurs with vendoring.)
   510  	imports := make(map[string]*types2.Package)
   511  	for i := 0; i < 3; i++ {
   512  		if _, err := Import(imports, "./././testdata/p", tmpdir, nil); err != nil {
   513  			t.Fatal(err)
   514  		}
   515  	}
   516  }
   517  
   518  func TestIssue15920(t *testing.T) {
   519  	skipSpecialPlatforms(t)
   520  
   521  	// This package only handles gc export data.
   522  	if runtime.Compiler != "gc" {
   523  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   524  	}
   525  
   526  	// On windows, we have to set the -D option for the compiler to avoid having a drive
   527  	// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
   528  	if runtime.GOOS == "windows" {
   529  		t.Skip("avoid dealing with relative paths/drive letters on windows")
   530  	}
   531  
   532  	compileAndImportPkg(t, "issue15920")
   533  }
   534  
   535  func TestIssue20046(t *testing.T) {
   536  	skipSpecialPlatforms(t)
   537  
   538  	// This package only handles gc export data.
   539  	if runtime.Compiler != "gc" {
   540  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   541  	}
   542  
   543  	// On windows, we have to set the -D option for the compiler to avoid having a drive
   544  	// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
   545  	if runtime.GOOS == "windows" {
   546  		t.Skip("avoid dealing with relative paths/drive letters on windows")
   547  	}
   548  
   549  	// "./issue20046".V.M must exist
   550  	pkg := compileAndImportPkg(t, "issue20046")
   551  	obj := lookupObj(t, pkg.Scope(), "V")
   552  	if m, index, indirect := types2.LookupFieldOrMethod(obj.Type(), false, nil, "M"); m == nil {
   553  		t.Fatalf("V.M not found (index = %v, indirect = %v)", index, indirect)
   554  	}
   555  }
   556  func TestIssue25301(t *testing.T) {
   557  	skipSpecialPlatforms(t)
   558  
   559  	// This package only handles gc export data.
   560  	if runtime.Compiler != "gc" {
   561  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   562  	}
   563  
   564  	// On windows, we have to set the -D option for the compiler to avoid having a drive
   565  	// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
   566  	if runtime.GOOS == "windows" {
   567  		t.Skip("avoid dealing with relative paths/drive letters on windows")
   568  	}
   569  
   570  	compileAndImportPkg(t, "issue25301")
   571  }
   572  
   573  func TestIssue25596(t *testing.T) {
   574  	skipSpecialPlatforms(t)
   575  
   576  	// This package only handles gc export data.
   577  	if runtime.Compiler != "gc" {
   578  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   579  	}
   580  
   581  	// On windows, we have to set the -D option for the compiler to avoid having a drive
   582  	// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
   583  	if runtime.GOOS == "windows" {
   584  		t.Skip("avoid dealing with relative paths/drive letters on windows")
   585  	}
   586  
   587  	compileAndImportPkg(t, "issue25596")
   588  }
   589  
   590  func importPkg(t *testing.T, path, srcDir string) *types2.Package {
   591  	pkg, err := Import(make(map[string]*types2.Package), path, srcDir, nil)
   592  	if err != nil {
   593  		t.Fatal(err)
   594  	}
   595  	return pkg
   596  }
   597  
   598  func compileAndImportPkg(t *testing.T, name string) *types2.Package {
   599  	tmpdir := mktmpdir(t)
   600  	defer os.RemoveAll(tmpdir)
   601  	compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"))
   602  	return importPkg(t, "./testdata/"+name, tmpdir)
   603  }
   604  
   605  func lookupObj(t *testing.T, scope *types2.Scope, name string) types2.Object {
   606  	if obj := scope.Lookup(name); obj != nil {
   607  		return obj
   608  	}
   609  	t.Fatalf("%s not found", name)
   610  	return nil
   611  }
   612  

View as plain text