Esempio n. 1
0
func (g *cpyGen) genTypeMethods(sym *symbol) {
	g.decl.Printf("\n/* methods for %s */\n", sym.gofmt())
	if sym.isNamed() {
		typ := sym.GoType().(*types.Named)
		for imeth := 0; imeth < typ.NumMethods(); imeth++ {
			m := typ.Method(imeth)
			if !m.Exported() {
				continue
			}
			mname := types.ObjectString(m, nil)
			msym := g.pkg.syms.sym(mname)
			if msym == nil {
				panic(fmt.Errorf(
					"gopy: could not find symbol for [%[1]T] (%#[1]v) (%[2]s)",
					m.Type(),
					m.Name()+" || "+m.FullName(),
				))
			}
			g._genFunc(sym, msym)
		}
	}
	g.impl.Printf("\n/* methods for %s */\n", sym.gofmt())
	g.impl.Printf("static PyMethodDef %s_methods[] = {\n", sym.cpyname)
	g.impl.Indent()
	if sym.isNamed() {
		typ := sym.GoType().(*types.Named)
		for imeth := 0; imeth < typ.NumMethods(); imeth++ {
			m := typ.Method(imeth)
			if !m.Exported() {
				continue
			}
			mname := types.ObjectString(m, nil)
			msym := g.pkg.syms.sym(mname)
			margs := "METH_VARARGS"
			sig := m.Type().Underlying().(*types.Signature)
			if sig.Params() == nil || sig.Params().Len() <= 0 {
				margs = "METH_NOARGS"
			}
			g.impl.Printf(
				"{%[1]q, (PyCFunction)cpy_func_%[2]s, %[3]s, %[4]q},\n",
				msym.goname,
				msym.id,
				margs,
				msym.doc,
			)
		}
	}
	g.impl.Printf("{NULL} /* sentinel */\n")
	g.impl.Outdent()
	g.impl.Printf("};\n\n")
}
Esempio n. 2
0
func TestImportedTypes(t *testing.T) {
	skipSpecialPlatforms(t)

	// This package only handles gc export data.
	if runtime.Compiler != "gc" {
		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
		return
	}

	for _, test := range importedObjectTests {
		s := strings.Split(test.name, ".")
		if len(s) != 2 {
			t.Fatal("inconsistent test data")
		}
		importPath := s[0]
		objName := s[1]

		pkg, err := Import(imports, importPath)
		if err != nil {
			t.Error(err)
			continue
		}

		obj := pkg.Scope().Lookup(objName)
		if obj == nil {
			t.Errorf("%s: object not found", test.name)
			continue
		}

		got := types.ObjectString(obj, types.RelativeTo(pkg))
		if got != test.want {
			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
		}
	}
}
Esempio n. 3
0
func (sym *symtab) addSymbol(obj types.Object) {
	fn := types.ObjectString(obj, nil)
	n := obj.Name()
	pkg := obj.Pkg()
	id := n
	if pkg != nil {
		id = pkg.Name() + "_" + n
	}
	switch obj.(type) {
	case *types.Const:
		sym.syms[fn] = &symbol{
			gopkg:   pkg,
			goobj:   obj,
			kind:    skConst,
			id:      id,
			goname:  n,
			cgoname: "cgo_const_" + id,
			cpyname: "cpy_const_" + id,
		}
		sym.addType(obj, obj.Type())

	case *types.Var:
		sym.syms[fn] = &symbol{
			gopkg:   pkg,
			goobj:   obj,
			kind:    skVar,
			id:      id,
			goname:  n,
			cgoname: "cgo_var_" + id,
			cpyname: "cpy_var_" + id,
		}
		sym.addType(obj, obj.Type())

	case *types.Func:
		sym.syms[fn] = &symbol{
			gopkg:   pkg,
			goobj:   obj,
			kind:    skFunc,
			id:      id,
			goname:  n,
			cgoname: "cgo_func_" + id,
			cpyname: "cpy_func_" + id,
		}
		sig := obj.Type().Underlying().(*types.Signature)
		sym.processTuple(sig.Params())
		sym.processTuple(sig.Results())

	case *types.TypeName:
		sym.addType(obj, obj.Type())

	default:
		panic(fmt.Errorf("gopy: handled object [%#v]", obj))
	}
}
Esempio n. 4
0
func (sym *symtab) addMethod(pkg *types.Package, obj types.Object, t types.Type, kind symkind, id, n string) {
	fn := types.ObjectString(obj, nil)
	kind |= skFunc
	sym.syms[fn] = &symbol{
		gopkg:   pkg,
		goobj:   obj,
		gotyp:   t,
		kind:    kind,
		id:      id,
		goname:  n,
		cgoname: "cgo_func_" + id,
		cpyname: "cpy_func_" + id,
	}
	sig := t.Underlying().(*types.Signature)
	sym.processTuple(sig.Results())
	sym.processTuple(sig.Params())
}
Esempio n. 5
0
func (g *cpyGen) genStructMethods(cpy Struct) {

	pkgname := cpy.Package().Name()

	g.decl.Printf("\n/* methods for %s.%s */\n", pkgname, cpy.GoName())
	typ := cpy.sym.GoType().(*types.Named)
	for i := 0; i < typ.NumMethods(); i++ {
		m := typ.Method(i)
		if !m.Exported() {
			continue
		}
		mname := types.ObjectString(m, nil)
		msym := g.pkg.syms.sym(mname)
		if msym == nil {
			panic(fmt.Errorf(
				"gopy: could not find symbol for %q",
				m.FullName(),
			))
		}
		g._genFunc(cpy.sym, msym)
	}

	g.impl.Printf("\n/* methods for %s.%s */\n", pkgname, cpy.GoName())
	g.impl.Printf("static PyMethodDef %s_methods[] = {\n", cpy.sym.cpyname)
	g.impl.Indent()
	for _, m := range cpy.meths {
		margs := "METH_VARARGS"
		if len(m.Signature().Params()) == 0 {
			margs = "METH_NOARGS"
		}
		g.impl.Printf(
			"{%[1]q, (PyCFunction)cpy_func_%[2]s, %[3]s, %[4]q},\n",
			m.GoName(),
			m.ID(),
			margs,
			m.Doc(),
		)
	}
	g.impl.Printf("{NULL} /* sentinel */\n")
	g.impl.Outdent()
	g.impl.Printf("};\n\n")
}
Esempio n. 6
0
File: guru.go Progetto: tsandall/opa
// ObjectString prints object obj relative to the query position.
func (qpos *queryPos) objectString(obj types.Object) string {
	return types.ObjectString(obj, types.RelativeTo(qpos.info.Pkg))
}
Esempio n. 7
0
func (r *referrersInitialResult) PrintPlain(printf printfFunc) {
	printf(r.obj, "references to %s",
		types.ObjectString(r.obj, types.RelativeTo(r.qinfo.Pkg)))
}
Esempio n. 8
0
func runImporterTest(t *testing.T, imp Importer, initmap map[*types.Package]InitData, test *importerTest) {
	pkg, err := imp(make(map[string]*types.Package), test.pkgpath)
	if err != nil {
		t.Error(err)
		return
	}

	if test.name != "" {
		obj := pkg.Scope().Lookup(test.name)
		if obj == nil {
			t.Errorf("%s: object not found", test.name)
			return
		}

		got := types.ObjectString(obj, types.RelativeTo(pkg))
		if got != test.want {
			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
		}

		if test.wantval != "" {
			gotval := obj.(*types.Const).Val().String()
			if gotval != test.wantval {
				t.Errorf("%s: got val %q; want val %q", test.name, gotval, test.wantval)
			}
		}
	}

	if len(test.wantinits) > 0 {
		initdata := initmap[pkg]
		found := false
		// Check that the package's own init function has the package's priority
		for _, pkginit := range initdata.Inits {
			if pkginit.InitFunc == test.wantinits[0] {
				if initdata.Priority != pkginit.Priority {
					t.Errorf("%s: got self priority %d; want %d", test.pkgpath, pkginit.Priority, initdata.Priority)
				}
				found = true
				break
			}
		}

		if !found {
			t.Errorf("%s: could not find expected function %q", test.pkgpath, test.wantinits[0])
		}

		// Each init function in the list other than the first one is a
		// dependency of the function immediately before it. Check that
		// the init functions appear in descending priority order.
		priority := initdata.Priority
		for _, wantdepinit := range test.wantinits[1:] {
			found = false
			for _, pkginit := range initdata.Inits {
				if pkginit.InitFunc == wantdepinit {
					if priority <= pkginit.Priority {
						t.Errorf("%s: got dep priority %d; want less than %d", test.pkgpath, pkginit.Priority, priority)
					}
					found = true
					priority = pkginit.Priority
					break
				}
			}

			if !found {
				t.Errorf("%s: could not find expected function %q", test.pkgpath, wantdepinit)
			}
		}
	}
}
Esempio n. 9
0
func (a *analysis) doTypeInfo(info *loader.PackageInfo, implements map[*types.Named]implementsFacts) {
	// We must not assume the corresponding SSA packages were
	// created (i.e. were transitively error-free).

	// IMPORTS
	for _, f := range info.Files {
		// Package decl.
		fi, offset := a.fileAndOffset(f.Name.Pos())
		fi.addLink(aLink{
			start: offset,
			end:   offset + len(f.Name.Name),
			title: "Package docs for " + info.Pkg.Path(),
			// TODO(adonovan): fix: we're putting the untrusted Path()
			// into a trusted field.  What's the appropriate sanitizer?
			href: "/pkg/" + info.Pkg.Path(),
		})

		// Import specs.
		for _, imp := range f.Imports {
			// Remove quotes.
			L := int(imp.End()-imp.Path.Pos()) - len(`""`)
			path, _ := strconv.Unquote(imp.Path.Value)
			fi, offset := a.fileAndOffset(imp.Path.Pos())
			fi.addLink(aLink{
				start: offset + 1,
				end:   offset + 1 + L,
				title: "Package docs for " + path,
				// TODO(adonovan): fix: we're putting the untrusted path
				// into a trusted field.  What's the appropriate sanitizer?
				href: "/pkg/" + path,
			})
		}
	}

	// RESOLUTION
	qualifier := types.RelativeTo(info.Pkg)
	for id, obj := range info.Uses {
		// Position of the object definition.
		pos := obj.Pos()
		Len := len(obj.Name())

		// Correct the position for non-renaming import specs.
		//  import "sync/atomic"
		//          ^^^^^^^^^^^
		if obj, ok := obj.(*types.PkgName); ok && id.Name == obj.Imported().Name() {
			// Assume this is a non-renaming import.
			// NB: not true for degenerate renamings: `import foo "foo"`.
			pos++
			Len = len(obj.Imported().Path())
		}

		if obj.Pkg() == nil {
			continue // don't mark up built-ins.
		}

		fi, offset := a.fileAndOffset(id.NamePos)
		fi.addLink(aLink{
			start: offset,
			end:   offset + len(id.Name),
			title: types.ObjectString(obj, qualifier),
			href:  a.posURL(pos, Len),
		})
	}

	// IMPLEMENTS & METHOD SETS
	for _, obj := range info.Defs {
		if obj, ok := obj.(*types.TypeName); ok {
			a.namedType(obj, implements)
		}
	}
}
Esempio n. 10
0
// ExampleInfo prints various facts recorded by the type checker in a
// types.Info struct: definitions of and references to each named object,
// and the type, value, and mode of every expression in the package.
func ExampleInfo() {
	// Parse a single source file.
	const input = `
package fib

type S string

var a, b, c = len(b), S(c), "hello"

func fib(x int) int {
	if x < 2 {
		return x
	}
	return fib(x-1) - fib(x-2)
}`
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "fib.go", input, 0)
	if err != nil {
		log.Fatal(err)
	}

	// Type-check the package.
	// We create an empty map for each kind of input
	// we're interested in, and Check populates them.
	info := types.Info{
		Types: make(map[ast.Expr]types.TypeAndValue),
		Defs:  make(map[*ast.Ident]types.Object),
		Uses:  make(map[*ast.Ident]types.Object),
	}
	var conf types.Config
	pkg, err := conf.Check("fib", fset, []*ast.File{f}, &info)
	if err != nil {
		log.Fatal(err)
	}

	// Print package-level variables in initialization order.
	fmt.Printf("InitOrder: %v\n\n", info.InitOrder)

	// For each named object, print the line and
	// column of its definition and each of its uses.
	fmt.Println("Defs and Uses of each named object:")
	usesByObj := make(map[types.Object][]string)
	for id, obj := range info.Uses {
		posn := fset.Position(id.Pos())
		lineCol := fmt.Sprintf("%d:%d", posn.Line, posn.Column)
		usesByObj[obj] = append(usesByObj[obj], lineCol)
	}
	var items []string
	for obj, uses := range usesByObj {
		sort.Strings(uses)
		item := fmt.Sprintf("%s:\n  defined at %s\n  used at %s",
			types.ObjectString(pkg, obj),
			fset.Position(obj.Pos()),
			strings.Join(uses, ", "))
		items = append(items, item)
	}
	sort.Strings(items) // sort by line:col, in effect
	fmt.Println(strings.Join(items, "\n"))
	fmt.Println()

	fmt.Println("Types and Values of each expression:")
	items = nil
	for expr, tv := range info.Types {
		var buf bytes.Buffer
		posn := fset.Position(expr.Pos())
		tvstr := tv.Type.String()
		if tv.Value != nil {
			tvstr += " = " + tv.Value.String()
		}
		// line:col | expr | mode : type = value
		fmt.Fprintf(&buf, "%2d:%2d | %-19s | %-7s : %s",
			posn.Line, posn.Column, exprString(fset, expr),
			mode(tv), tvstr)
		items = append(items, buf.String())
	}
	sort.Strings(items)
	fmt.Println(strings.Join(items, "\n"))

	// Output:
	// InitOrder: [c = "hello" b = S(c) a = len(b)]
	//
	// Defs and Uses of each named object:
	// builtin len:
	//   defined at -
	//   used at 6:15
	// func fib(x int) int:
	//   defined at fib.go:8:6
	//   used at 12:20, 12:9
	// type S string:
	//   defined at fib.go:4:6
	//   used at 6:23
	// type int int:
	//   defined at -
	//   used at 8:12, 8:17
	// type string string:
	//   defined at -
	//   used at 4:8
	// var b S:
	//   defined at fib.go:6:8
	//   used at 6:19
	// var c string:
	//   defined at fib.go:6:11
	//   used at 6:25
	// var x int:
	//   defined at fib.go:8:10
	//   used at 10:10, 12:13, 12:24, 9:5
	//
	// Types and Values of each expression:
	//  4: 8 | string              | type    : string
	//  6:15 | len                 | builtin : func(string) int
	//  6:15 | len(b)              | value   : int
	//  6:19 | b                   | var     : fib.S
	//  6:23 | S                   | type    : fib.S
	//  6:23 | S(c)                | value   : fib.S
	//  6:25 | c                   | var     : string
	//  6:29 | "hello"             | value   : string = "hello"
	//  8:12 | int                 | type    : int
	//  8:17 | int                 | type    : int
	//  9: 5 | x                   | var     : int
	//  9: 5 | x < 2               | value   : untyped bool
	//  9: 9 | 2                   | value   : int = 2
	// 10:10 | x                   | var     : int
	// 12: 9 | fib                 | value   : func(x int) int
	// 12: 9 | fib(x - 1)          | value   : int
	// 12: 9 | fib(x-1) - fib(x-2) | value   : int
	// 12:13 | x                   | var     : int
	// 12:13 | x - 1               | value   : int
	// 12:15 | 1                   | value   : int = 1
	// 12:20 | fib                 | value   : func(x int) int
	// 12:20 | fib(x - 2)          | value   : int
	// 12:24 | x                   | var     : int
	// 12:24 | x - 2               | value   : int
	// 12:26 | 2                   | value   : int = 2
}
Esempio n. 11
0
func (g *goGen) genTypeMethods(sym *symbol) {
	if !sym.isNamed() {
		return
	}

	typ := sym.GoType().(*types.Named)
	for imeth := 0; imeth < typ.NumMethods(); imeth++ {
		m := typ.Method(imeth)
		if !m.Exported() {
			continue
		}

		mname := types.ObjectString(m, nil)
		msym := g.pkg.syms.sym(mname)
		if msym == nil {
			panic(fmt.Errorf(
				"gopy: could not find symbol for [%[1]T] (%#[1]v) (%[2]s)",
				m.Type(),
				m.Name()+" || "+m.FullName(),
			))
		}
		g.Printf("//export cgo_func_%[1]s\n", msym.id)
		g.Printf("func cgo_func_%[1]s(self %[2]s",
			msym.id,
			sym.cgoname,
		)
		sig := m.Type().(*types.Signature)
		params := sig.Params()
		if params != nil {
			for i := 0; i < params.Len(); i++ {
				arg := params.At(i)
				sarg := g.pkg.syms.symtype(arg.Type())
				if sarg == nil {
					panic(fmt.Errorf(
						"gopy: could not find symbol for [%T]",
						arg.Type(),
					))
				}
				g.Printf(", arg%03d %s", i, sarg.cgotypename())
			}
		}
		g.Printf(") ")
		res := sig.Results()
		if res != nil {
			g.Printf("(")
			for i := 0; i < res.Len(); i++ {
				if i > 0 {
					g.Printf(", ")
				}
				ret := res.At(i)
				sret := g.pkg.syms.symtype(ret.Type())
				if sret == nil {
					panic(fmt.Errorf(
						"gopy: could not find symbol for [%T]",
						ret.Type(),
					))
				}
				g.Printf("%s", sret.cgotypename())
			}
			g.Printf(")")
		}
		g.Printf(" {\n")
		g.Indent()

		if res != nil {
			for i := 0; i < res.Len(); i++ {
				if i > 0 {
					g.Printf(", ")
				}
				g.Printf("res%03d", i)
			}
			if res.Len() > 0 {
				g.Printf(" := ")
			}
		}
		if sym.isBasic() {
			g.Printf("(*%s)(unsafe.Pointer(&self)).%s(",
				sym.gofmt(),
				msym.goname,
			)
		} else {
			g.Printf("(*%s)(unsafe.Pointer(self)).%s(",
				sym.gofmt(),
				msym.goname,
			)
		}

		if params != nil {
			for i := 0; i < params.Len(); i++ {
				if i > 0 {
					g.Printf(", ")
				}
				sarg := g.pkg.syms.symtype(params.At(i).Type())
				if needWrapType(sarg.GoType()) {
					g.Printf("*(*%s)(unsafe.Pointer(arg%03d))",
						sarg.gofmt(),
						i,
					)
				} else {
					g.Printf("arg%03d", i)
				}
			}
		}
		g.Printf(")\n")

		if res == nil || res.Len() <= 0 {
			g.Outdent()
			g.Printf("}\n\n")
			continue
		}

		g.Printf("return ")
		for i := 0; i < res.Len(); i++ {
			if i > 0 {
				g.Printf(", ")
			}
			sret := g.pkg.syms.symtype(res.At(i).Type())
			if needWrapType(sret.GoType()) {
				g.Printf(
					"%s(unsafe.Pointer(&",
					sret.cgoname,
				)
			}
			g.Printf("res%03d", i)
			if needWrapType(sret.GoType()) {
				g.Printf("))")
			}
		}
		g.Printf("\n")

		g.Outdent()
		g.Printf("}\n\n")
	}
}
Esempio n. 12
0
// process collects informations about a go package.
func (p *Package) process() error {
	var err error

	funcs := make(map[string]Func)
	structs := make(map[string]Struct)

	scope := p.pkg.Scope()
	for _, name := range scope.Names() {
		obj := scope.Lookup(name)
		if !obj.Exported() {
			continue
		}

		p.n++
		p.syms.addSymbol(obj)
	}

	for _, name := range scope.Names() {
		obj := scope.Lookup(name)
		if !obj.Exported() {
			continue
		}

		switch obj := obj.(type) {
		case *types.Const:
			p.addConst(obj)

		case *types.Var:
			p.addVar(obj)

		case *types.Func:
			funcs[name], err = newFuncFrom(p, "", obj, obj.Type().(*types.Signature))
			if err != nil {
				return err
			}

		case *types.TypeName:
			named := obj.Type().(*types.Named)
			switch typ := named.Underlying().(type) {
			case *types.Struct:
				structs[name], err = newStruct(p, obj)
				if err != nil {
					return err
				}

			case *types.Basic:
				// ok. handled by p.syms-types

			case *types.Array:
				// ok. handled by p.syms-types

			case *types.Interface:
				// ok. handled by p.syms-types

			case *types.Signature:
				// ok. handled by p.syms-types

			case *types.Slice:
				// ok. handled by p.syms-types

			default:
				//TODO(sbinet)
				panic(fmt.Errorf("not yet supported: %v (%T)", typ, obj))
			}

		default:
			//TODO(sbinet)
			panic(fmt.Errorf("not yet supported: %v (%T)", obj, obj))
		}

	}

	// remove ctors from funcs.
	// add methods.
	for sname, s := range structs {
		for name, fct := range funcs {
			if fct.Return() == nil {
				continue
			}
			if fct.Return() == s.GoType() {
				delete(funcs, name)
				fct.doc = p.getDoc(sname, scope.Lookup(name))
				fct.ctor = true
				s.ctors = append(s.ctors, fct)
				structs[sname] = s
			}
		}

		ptyp := types.NewPointer(s.GoType())
		p.syms.addType(nil, ptyp)
		mset := types.NewMethodSet(ptyp)
		for i := 0; i < mset.Len(); i++ {
			meth := mset.At(i)
			if !meth.Obj().Exported() {
				continue
			}
			m, err := newFuncFrom(p, sname, meth.Obj(), meth.Type().(*types.Signature))
			if err != nil {
				return err
			}
			s.meths = append(s.meths, m)
			if isStringer(meth.Obj()) {
				s.prots |= ProtoStringer
			}
		}
		p.addStruct(s)
	}

	for _, fct := range funcs {
		p.addFunc(fct)
	}

	// attach docstrings to methods
	for _, n := range p.syms.names() {
		sym := p.syms.syms[n]
		if !sym.isNamed() {
			continue
		}
		switch typ := sym.GoType().(type) {
		case *types.Named:
			for i := 0; i < typ.NumMethods(); i++ {
				m := typ.Method(i)
				if !m.Exported() {
					continue
				}
				doc := p.getDoc(sym.goname, m)
				mname := types.ObjectString(m, nil)
				msym := p.syms.sym(mname)
				if msym == nil {
					panic(fmt.Errorf(
						"gopy: could not retrieve symbol for %q",
						m.FullName(),
					))
				}
				msym.doc = doc
			}
		}
	}
	return err
}
Esempio n. 13
0
func TestStdlib(t *testing.T) {
	if runtime.GOOS == "android" {
		t.Skipf("incomplete std lib on %s", runtime.GOOS)
	}
	if testing.Short() {
		t.Skip("skipping in short mode; uses tons of memory (golang.org/issue/14113)")
	}

	runtime.GC()
	t0 := time.Now()
	var memstats runtime.MemStats
	runtime.ReadMemStats(&memstats)
	alloc := memstats.Alloc

	// Load, parse and type-check the program.
	ctxt := build.Default // copy
	ctxt.GOPATH = ""      // disable GOPATH
	conf := loader.Config{Build: &ctxt}
	for _, path := range buildutil.AllPackages(conf.Build) {
		conf.ImportWithTests(path)
	}

	prog, err := conf.Load()
	if err != nil {
		t.Fatalf("Load failed: %v", err)
	}

	t1 := time.Now()
	runtime.GC()
	runtime.ReadMemStats(&memstats)

	numPkgs := len(prog.AllPackages)
	if want := 205; numPkgs < want {
		t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
	}

	// Dump package members.
	if false {
		for pkg := range prog.AllPackages {
			fmt.Printf("Package %s:\n", pkg.Path())
			scope := pkg.Scope()
			qualifier := types.RelativeTo(pkg)
			for _, name := range scope.Names() {
				if ast.IsExported(name) {
					fmt.Printf("\t%s\n", types.ObjectString(scope.Lookup(name), qualifier))
				}
			}
			fmt.Println()
		}
	}

	// Check that Test functions for io/ioutil, regexp and
	// compress/bzip2 are all simultaneously present.
	// (The apparent cycle formed when augmenting all three of
	// these packages by their tests was the original motivation
	// for reporting b/7114.)
	//
	// compress/bzip2.TestBitReader in bzip2_test.go    imports io/ioutil
	// io/ioutil.TestTempFile       in tempfile_test.go imports regexp
	// regexp.TestRE2Search         in exec_test.go     imports compress/bzip2
	for _, test := range []struct{ pkg, fn string }{
		{"io/ioutil", "TestTempFile"},
		{"regexp", "TestRE2Search"},
		{"compress/bzip2", "TestBitReader"},
	} {
		info := prog.Imported[test.pkg]
		if info == nil {
			t.Errorf("failed to load package %q", test.pkg)
			continue
		}
		obj, _ := info.Pkg.Scope().Lookup(test.fn).(*types.Func)
		if obj == nil {
			t.Errorf("package %q has no func %q", test.pkg, test.fn)
			continue
		}
	}

	// Dump some statistics.

	// determine line count
	var lineCount int
	prog.Fset.Iterate(func(f *token.File) bool {
		lineCount += f.LineCount()
		return true
	})

	t.Log("GOMAXPROCS:           ", runtime.GOMAXPROCS(0))
	t.Log("#Source lines:        ", lineCount)
	t.Log("Load/parse/typecheck: ", t1.Sub(t0))
	t.Log("#MB:                  ", int64(memstats.Alloc-alloc)/1000000)
}