func TestStdlib(t *testing.T) { defer func(saved func(format string, args ...interface{})) { logf = saved }(logf) logf = t.Errorf ctxt := build.Default // copy // Enumerate $GOROOT packages. saved := ctxt.GOPATH ctxt.GOPATH = "" // disable GOPATH during AllPackages pkgs := buildutil.AllPackages(&ctxt) ctxt.GOPATH = saved // Throw in a number of go.tools packages too. pkgs = append(pkgs, "golang.org/x/tools/cmd/godoc", "golang.org/x/tools/refactor/lexical") // Load, parse and type-check the program. conf := loader.Config{Build: &ctxt} for _, path := range pkgs { conf.ImportWithTests(path) } iprog, err := conf.Load() if err != nil { t.Fatalf("Load failed: %v", err) } // This test ensures that Structure doesn't panic and that // its internal sanity-checks against go/types don't fail. for pkg, info := range iprog.AllPackages { _ = Structure(iprog.Fset, pkg, &info.Info, info.Files) } }
// Create unexporter func NewUnexporter(o *Config) (*unexporter, error) { var conf loader.Config for _, package_name := range buildutil.AllPackages(&build.Default) { conf.ImportWithTests(package_name) } program, err := conf.Load() if err != nil { return nil, err } if program.Package(o.Pkg) == nil { return nil, errors.New(fmt.Sprintf("'%s' is not a valid package", o.Pkg)) } if o.Debug { pkg := program.Package(o.Pkg).Pkg fmt.Printf("finding unused identifiers for %s (%s)\n", pkg.Name(), pkg.Path()) } unexporter := &unexporter{ Program: program, MainPackage: program.Package(o.Pkg), Verbose: o.Debug, } unexporter.run() return unexporter, nil }
func TestAllPackages(t *testing.T) { all := buildutil.AllPackages(&build.Default) set := make(map[string]bool) for _, pkg := range all { set[pkg] = true } const wantAtLeast = 250 if len(all) < wantAtLeast { t.Errorf("Found only %d packages, want at least %d", len(all), wantAtLeast) } for _, want := range []string{"fmt", "crypto/sha256", "golang.org/x/tools/go/buildutil"} { if !set[want] { t.Errorf("Package %q not found; got %s", want, all) } } }
func TestStdlib(t *testing.T) { // Load, parse and type-check the program. t0 := time.Now() alloc0 := bytesAllocated() // 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) { if skip[path] { continue } conf.ImportWithTests(path) } iprog, err := conf.Load() if err != nil { t.Fatalf("Load failed: %v", err) } t1 := time.Now() alloc1 := bytesAllocated() // Create SSA packages. var mode ssa.BuilderMode // Comment out these lines during benchmarking. Approx SSA build costs are noted. mode |= ssa.SanityCheckFunctions // + 2% space, + 4% time mode |= ssa.GlobalDebug // +30% space, +18% time prog := ssautil.CreateProgram(iprog, mode) t2 := time.Now() // Build SSA. prog.Build() t3 := time.Now() alloc3 := bytesAllocated() numPkgs := len(prog.AllPackages()) if want := 140; numPkgs < want { t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want) } // Keep iprog reachable until after we've measured memory usage. if len(iprog.AllPackages) == 0 { print() // unreachable } allFuncs := ssautil.AllFunctions(prog) // Check that all non-synthetic functions have distinct names. // Synthetic wrappers for exported methods should be distinct too, // except for unexported ones (explained at (*Function).RelString). byName := make(map[string]*ssa.Function) for fn := range allFuncs { if fn.Synthetic == "" || ast.IsExported(fn.Name()) { str := fn.String() prev := byName[str] byName[str] = fn if prev != nil { t.Errorf("%s: duplicate function named %s", prog.Fset.Position(fn.Pos()), str) t.Errorf("%s: (previously defined here)", prog.Fset.Position(prev.Pos())) } } } // Dump some statistics. var numInstrs int for fn := range allFuncs { for _, b := range fn.Blocks { numInstrs += len(b.Instrs) } } // determine line count var lineCount int prog.Fset.Iterate(func(f *token.File) bool { lineCount += f.LineCount() return true }) // NB: when benchmarking, don't forget to clear the debug + // sanity builder flags for better performance. t.Log("GOMAXPROCS: ", runtime.GOMAXPROCS(0)) t.Log("#Source lines: ", lineCount) t.Log("Load/parse/typecheck: ", t1.Sub(t0)) t.Log("SSA create: ", t2.Sub(t1)) t.Log("SSA build: ", t3.Sub(t2)) // SSA stats: t.Log("#Packages: ", numPkgs) t.Log("#Functions: ", len(allFuncs)) t.Log("#Instructions: ", numInstrs) t.Log("#MB AST+types: ", int64(alloc1-alloc0)/1e6) t.Log("#MB SSA: ", int64(alloc3-alloc1)/1e6) }
func TestStdlib(t *testing.T) { if !*runStdlibTest { t.Skip("skipping (slow) stdlib test (use --stdlib)") } // Load, parse and type-check the program. ctxt := build.Default // copy ctxt.GOPATH = "" // disable GOPATH conf := loader.Config{Build: &ctxt} if _, err := conf.FromArgs(buildutil.AllPackages(conf.Build), true); err != nil { t.Errorf("FromArgs failed: %v", err) return } iprog, err := conf.Load() if err != nil { t.Fatalf("Load failed: %v", err) } // Create SSA packages. prog := ssautil.CreateProgram(iprog, 0) prog.BuildAll() numPkgs := len(prog.AllPackages()) if want := 240; numPkgs < want { t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want) } // Determine the set of packages/tests to analyze. var testPkgs []*ssa.Package for _, info := range iprog.InitialPackages() { testPkgs = append(testPkgs, prog.Package(info.Pkg)) } testmain := prog.CreateTestMainPackage(testPkgs...) if testmain == nil { t.Fatal("analysis scope has tests") } // Run the analysis. config := &Config{ Reflection: false, // TODO(adonovan): fix remaining bug in rVCallConstraint, then enable. BuildCallGraph: true, Mains: []*ssa.Package{testmain}, } // TODO(adonovan): add some query values (affects track bits). t0 := time.Now() result, err := Analyze(config) if err != nil { t.Fatal(err) // internal error in pointer analysis } _ = result // TODO(adonovan): measure something t1 := time.Now() // Dump some statistics. allFuncs := ssautil.AllFunctions(prog) var numInstrs int for fn := range allFuncs { for _, b := range fn.Blocks { numInstrs += len(b.Instrs) } } // determine line count var lineCount int prog.Fset.Iterate(func(f *token.File) bool { lineCount += f.LineCount() return true }) t.Log("#Source lines: ", lineCount) t.Log("#Instructions: ", numInstrs) t.Log("Pointer analysis: ", t1.Sub(t0)) }
func TestBExportData_stdlib(t *testing.T) { if runtime.GOOS == "android" { t.Skipf("incomplete std lib on %s", runtime.GOOS) } // Load, parse and type-check the program. ctxt := build.Default // copy ctxt.GOPATH = "" // disable GOPATH conf := loader.Config{ Build: &ctxt, AllowErrors: true, } for _, path := range buildutil.AllPackages(conf.Build) { conf.Import(path) } // Create a package containing type and value errors to ensure // they are properly encoded/decoded. f, err := conf.ParseFile("haserrors/haserrors.go", `package haserrors const UnknownValue = "" + 0 type UnknownType undefined `) if err != nil { t.Fatal(err) } conf.CreateFromFiles("haserrors", f) prog, err := conf.Load() if err != nil { t.Fatalf("Load failed: %v", err) } numPkgs := len(prog.AllPackages) if want := 248; numPkgs < want { t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want) } for pkg, info := range prog.AllPackages { if info.Files == nil { continue // empty directory } exportdata := gcimporter.BExportData(conf.Fset, pkg) imports := make(map[string]*types.Package) fset2 := token.NewFileSet() n, pkg2, err := gcimporter.BImportData(fset2, imports, exportdata, pkg.Path()) if err != nil { t.Errorf("BImportData(%s): %v", pkg.Path(), err) continue } if n != len(exportdata) { t.Errorf("BImportData(%s) decoded %d bytes, want %d", pkg.Path(), n, len(exportdata)) } // Compare the packages' corresponding members. for _, name := range pkg.Scope().Names() { if !ast.IsExported(name) { continue } obj1 := pkg.Scope().Lookup(name) obj2 := pkg2.Scope().Lookup(name) if obj2 == nil { t.Errorf("%s.%s not found, want %s", pkg.Path(), name, obj1) continue } fl1 := fileLine(conf.Fset, obj1) fl2 := fileLine(fset2, obj2) if fl1 != fl2 { t.Errorf("%s.%s: got posn %s, want %s", pkg.Path(), name, fl2, fl1) } if err := equalObj(obj1, obj2); err != nil { t.Errorf("%s.%s: %s\ngot: %s\nwant: %s", pkg.Path(), name, err, obj2, obj1) } } } }
func TestStdlib(t *testing.T) { if runtime.GOOS == "android" { t.Skipf("incomplete std lib on %s", runtime.GOOS) } 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) }