// 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 }
// 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 }
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 }
// 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 }
"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"})