func runImporterTest(t *testing.T, imp types.Importer, test *importerTest) { pkg, err := imp(make(map[string]*types.Package), test.pkgpath) if err != nil { t.Error(err) return } obj := pkg.Scope().Lookup(test.name) if obj == nil { t.Errorf("%s: object not found", test.name) return } got := types.ObjectString(pkg, obj) 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) } } }
func TestImportedTypes(t *testing.T) { // This package does not handle gccgo export data. if runtime.Compiler == "gccgo" { 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(pkg, obj) if got != test.want { t.Errorf("%s: got %q; want %q", test.name, got, test.want) } } }
func (r *resolver) use(id *ast.Ident, env Environment) { if id.Name == "_" { return // an error } obj, _ := env.Lookup(id.Name) if obj == nil { logf("%s: lookup of %s failed\n", r.fset.Position(id.Pos()), id.Name) } else if want := r.info.Uses[id]; obj != want { // sanity check against go/types resolver logf("%s: internal error: lookup of %s yielded wrong object: got %v (%s), want %v\n", r.fset.Position(id.Pos()), id.Name, types.ObjectString(r.pkg, obj), r.fset.Position(obj.Pos()), want) } if trace { logf("use %s = %v in %s\n", id.Name, types.ObjectString(r.pkg, obj), env) } r.result.Refs[obj] = append(r.result.Refs[obj], Reference{id, env}) }
func (r *resolver) defineObject(b *Block, name string, obj types.Object) { if obj.Name() == "_" { return } i := len(b.bindings) b.bindings = append(b.bindings, obj) b.index[name] = i if trace { logf("def %s = %s in %s\n", name, types.ObjectString(r.pkg, obj), b) } r.result.Defs[obj] = b }
// ObjectString prints object obj relative to the query position. func (qpos *QueryPos) ObjectString(obj types.Object) string { return types.ObjectString(qpos.info.Pkg, obj) }
func TestStdlib(t *testing.T) { runtime.GC() t0 := time.Now() var memstats runtime.MemStats runtime.ReadMemStats(&memstats) alloc := memstats.Alloc // Load, parse and type-check the program. var conf loader.Config for _, path := range allPackages() { if err := conf.ImportWithTests(path); err != nil { t.Error(err) } } 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() for _, name := range scope.Names() { if ast.IsExported(name) { fmt.Printf("\t%s\n", types.ObjectString(pkg, scope.Lookup(name))) } } 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) }
func runImporterTest(t *testing.T, imp types.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(pkg, obj) 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) } } } }
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 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(info.Pkg, obj), href: a.posURL(pos, Len), }) } // IMPLEMENTS & METHOD SETS for _, obj := range info.Defs { if obj, ok := obj.(*types.TypeName); ok { a.namedType(obj, implements) } } }