예제 #1
0
// Name = identifier | "?" | QualifiedName .
//
// If materializePkg is set, the returned package is guaranteed to be set.
// For fully qualified names, the returned package may be a fake package
// (without name, scope, and not in the p.imports map), created for the
// sole purpose of providing a package path. Fake packages are created
// when the package id is not found in the p.imports map; in that case
// we cannot create a real package because we don't have a package name.
// For non-qualified names, the returned package is the imported package.
//
func (p *parser) parseName(materializePkg bool) (pkg *types.Package, name string) {
	switch p.tok {
	case scanner.Ident:
		pkg = p.imports[p.id]
		name = p.lit
		p.next()
	case '?':
		// anonymous
		pkg = p.imports[p.id]
		p.next()
	case '@':
		// exported name prefixed with package path
		var id string
		id, name = p.parseQualifiedName()
		if materializePkg {
			// we don't have a package name - if the package
			// doesn't exist yet, create a fake package instead
			pkg = p.getPkg(id, "")
			if pkg == nil {
				pkg = types.NewPackage(id, "")
			}
		}
	default:
		p.error("name expected")
	}
	return
}
예제 #2
0
// getPkg returns the package for a given id. If the package is
// not found but we have a package name, create the package and
// add it to the p.imports map.
//
func (p *parser) getPkg(id, name string) *types.Package {
	// package unsafe is not in the imports map - handle explicitly
	if id == "unsafe" {
		return types.Unsafe
	}
	pkg := p.imports[id]
	if pkg == nil && name != "" {
		pkg = types.NewPackage(id, name)
		p.imports[id] = pkg
	}
	return pkg
}
예제 #3
0
func (imp *importer) newPackageInfo(path string) *PackageInfo {
	pkg := types.NewPackage(path, "")
	info := &PackageInfo{
		Pkg: pkg,
		Info: types.Info{
			Types:      make(map[ast.Expr]types.TypeAndValue),
			Defs:       make(map[*ast.Ident]types.Object),
			Uses:       make(map[*ast.Ident]types.Object),
			Implicits:  make(map[ast.Node]types.Object),
			Scopes:     make(map[ast.Node]*types.Scope),
			Selections: make(map[*ast.SelectorExpr]*types.Selection),
		},
	}

	// Use a copy of the types.Config so we can vary IgnoreFuncBodies.
	tc := imp.conf.TypeChecker
	tc.IgnoreFuncBodies = false
	if f := imp.conf.TypeCheckFuncBodies; f != nil {
		tc.IgnoreFuncBodies = !f(path)
	}
	tc.Import = imp.doImport // doImport wraps the user's importfn, effectively

	// The default error reporter just prints the errors.
	dfltError := tc.Error
	if dfltError == nil {
		dfltError = func(e error) { fmt.Fprintln(os.Stderr, e) }
	}
	// Wrap the error reporter to also collect them.
	tc.Error = func(e error) {
		info.Errors = append(info.Errors, e)
		dfltError(e)
	}

	info.checker = types.NewChecker(&tc, imp.conf.fset(), pkg, &info.Info)
	imp.prog.AllPackages[pkg] = info
	return info
}
예제 #4
0
// CreateTestMainPackage creates and returns a synthetic "main"
// package that runs all the tests of the supplied packages, similar
// to the one that would be created by the 'go test' tool.
//
// It returns nil if the program contains no tests.
//
func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package {
	if len(pkgs) == 0 {
		return nil
	}
	testmain := &Package{
		Prog:    prog,
		Members: make(map[string]Member),
		values:  make(map[types.Object]Value),
		Object:  types.NewPackage("testmain", "testmain"),
	}

	// Build package's init function.
	init := &Function{
		name:      "init",
		Signature: new(types.Signature),
		Synthetic: "package initializer",
		Pkg:       testmain,
		Prog:      prog,
	}
	init.startBody()
	// TODO(adonovan): use lexical order.
	var expfuncs []*Function // all exported functions of *_test.go in pkgs, unordered
	for _, pkg := range pkgs {
		if pkg.Prog != prog {
			panic("wrong Program")
		}
		// Initialize package to test.
		var v Call
		v.Call.Value = pkg.init
		v.setType(types.NewTuple())
		init.emit(&v)

		// Enumerate its possible tests/benchmarks.
		for _, mem := range pkg.Members {
			if f, ok := mem.(*Function); ok &&
				ast.IsExported(f.Name()) &&
				strings.HasSuffix(prog.Fset.Position(f.Pos()).Filename, "_test.go") {
				expfuncs = append(expfuncs, f)
			}
		}
	}
	init.emit(new(Return))
	init.finishBody()
	testmain.init = init
	testmain.Object.MarkComplete()
	testmain.Members[init.name] = init

	testingPkg := prog.ImportedPackage("testing")
	if testingPkg == nil {
		// If the program doesn't import "testing", it can't
		// contain any tests.
		// TODO(adonovan): but it might contain Examples.
		// Support them (by just calling them directly).
		return nil
	}
	testingMain := testingPkg.Func("Main")
	testingMainParams := testingMain.Signature.Params()

	// The generated code is as if compiled from this:
	//
	// func main() {
	//      match      := func(_, _ string) (bool, error) { return true, nil }
	//      tests      := []testing.InternalTest{{"TestFoo", TestFoo}, ...}
	//      benchmarks := []testing.InternalBenchmark{...}
	//      examples   := []testing.InternalExample{...}
	// 	testing.Main(match, tests, benchmarks, examples)
	// }

	main := &Function{
		name:      "main",
		Signature: new(types.Signature),
		Synthetic: "test main function",
		Prog:      prog,
		Pkg:       testmain,
	}

	matcher := &Function{
		name:      "matcher",
		Signature: testingMainParams.At(0).Type().(*types.Signature),
		Synthetic: "test matcher predicate",
		parent:    main,
		Pkg:       testmain,
		Prog:      prog,
	}
	main.AnonFuncs = append(main.AnonFuncs, matcher)
	matcher.startBody()
	matcher.emit(&Return{Results: []Value{vTrue, nilConst(types.Universe.Lookup("error").Type())}})
	matcher.finishBody()

	main.startBody()
	var c Call
	c.Call.Value = testingMain

	tests := testMainSlice(main, expfuncs, "Test", testingMainParams.At(1).Type())
	benchmarks := testMainSlice(main, expfuncs, "Benchmark", testingMainParams.At(2).Type())
	examples := testMainSlice(main, expfuncs, "Example", testingMainParams.At(3).Type())
	_, noTests := tests.(*Const) // i.e. nil slice
	_, noBenchmarks := benchmarks.(*Const)
	_, noExamples := examples.(*Const)
	if noTests && noBenchmarks && noExamples {
		return nil
	}

	c.Call.Args = []Value{matcher, tests, benchmarks, examples}
	// Emit: testing.Main(nil, tests, benchmarks, examples)
	emitTailCall(main, &c)
	main.finishBody()

	testmain.Members["main"] = main

	if prog.mode&LogPackages != 0 {
		testmain.WriteTo(os.Stderr)
	}

	if prog.mode&SanityCheckFunctions != 0 {
		sanityCheckPackage(testmain)
	}

	prog.packages[testmain.Object] = testmain

	return testmain
}
예제 #5
0
	"reflect"
	"unsafe"

	"github.com/nathankerr/godocbook/Godeps/_workspace/src/code.google.com/p/go.tools/go/ssa"
	"github.com/nathankerr/godocbook/Godeps/_workspace/src/code.google.com/p/go.tools/go/types"
)

type opaqueType struct {
	types.Type
	name string
}

func (t *opaqueType) String() string { return t.name }

// A bogus "reflect" type-checker package.  Shared across interpreters.
var reflectTypesPackage = types.NewPackage("reflect", "reflect")

// rtype is the concrete type the interpreter uses to implement the
// reflect.Type interface.  Since its type is opaque to the target
// language, we use a types.Basic.
//
// type rtype <opaque>
var rtypeType = makeNamedType("rtype", &opaqueType{nil, "rtype"})

// error is an (interpreted) named type whose underlying type is string.
// The interpreter uses it for all implementations of the built-in error
// interface that it creates.
// We put it in the "reflect" package for expedience.
//
// type error string
var errorType = makeNamedType("error", &opaqueType{nil, "error"})