| // Copyright 2014 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Incomplete source tree on Android. | |
| //go:build !android | |
| // +build !android | |
| package pointer | |
| // This file runs the pointer analysis on all packages and tests beneath | |
| // $GOROOT. It provides a "smoke test" that the analysis doesn't crash | |
| // on a large input, and a benchmark for performance measurement. | |
| // | |
| // Because it is relatively slow, the --stdlib flag must be enabled for | |
| // this test to run: | |
| // % go test -v golang.org/x/tools/go/pointer --stdlib | |
| import ( | |
| "flag" | |
| "go/token" | |
| "testing" | |
| "time" | |
| "golang.org/x/tools/go/packages" | |
| "golang.org/x/tools/go/ssa" | |
| "golang.org/x/tools/go/ssa/ssautil" | |
| ) | |
| var runStdlibTest = flag.Bool("stdlib", false, "Run the (slow) stdlib test") | |
| func TestStdlib(t *testing.T) { | |
| if !*runStdlibTest { | |
| t.Skip("skipping (slow) stdlib test (use --stdlib)") | |
| } | |
| cfg := &packages.Config{ | |
| Mode: packages.LoadAllSyntax, | |
| // Create test main packages with a main function. | |
| Tests: true, | |
| } | |
| pkgs, err := packages.Load(cfg, "std") | |
| if err != nil || packages.PrintErrors(pkgs) > 0 { | |
| t.Fatalf("Load failed: %v", err) | |
| } | |
| // Create SSA packages. | |
| prog, _ := ssautil.AllPackages(pkgs, ssa.InstantiateGenerics) | |
| prog.Build() | |
| 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 mains []*ssa.Package | |
| for _, ssapkg := range prog.AllPackages() { | |
| if ssapkg.Pkg.Name() == "main" && ssapkg.Func("main") != nil { | |
| mains = append(mains, ssapkg) | |
| } | |
| } | |
| if mains == nil { | |
| t.Fatal("no tests found in analysis scope") | |
| } | |
| // Run the analysis. | |
| config := &Config{ | |
| Reflection: false, // TODO(adonovan): fix remaining bug in rVCallConstraint, then enable. | |
| BuildCallGraph: true, | |
| Mains: mains, | |
| } | |
| // 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)) | |
| } |