1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Incomplete source tree on Android.
6
7// +build !android
8
9package pointer
10
11// This file runs the pointer analysis on all packages and tests beneath
12// $GOROOT.  It provides a "smoke test" that the analysis doesn't crash
13// on a large input, and a benchmark for performance measurement.
14//
15// Because it is relatively slow, the --stdlib flag must be enabled for
16// this test to run:
17//    % go test -v golang.org/x/tools/go/pointer --stdlib
18
19import (
20	"flag"
21	"go/build"
22	"go/token"
23	"testing"
24	"time"
25
26	"golang.org/x/tools/go/buildutil"
27	"golang.org/x/tools/go/loader"
28	"golang.org/x/tools/go/ssa"
29	"golang.org/x/tools/go/ssa/ssautil"
30)
31
32var runStdlibTest = flag.Bool("stdlib", false, "Run the (slow) stdlib test")
33
34func TestStdlib(t *testing.T) {
35	if !*runStdlibTest {
36		t.Skip("skipping (slow) stdlib test (use --stdlib)")
37	}
38
39	// Load, parse and type-check the program.
40	ctxt := build.Default // copy
41	ctxt.GOPATH = ""      // disable GOPATH
42	conf := loader.Config{Build: &ctxt}
43	if _, err := conf.FromArgs(buildutil.AllPackages(conf.Build), true); err != nil {
44		t.Errorf("FromArgs failed: %v", err)
45		return
46	}
47
48	iprog, err := conf.Load()
49	if err != nil {
50		t.Fatalf("Load failed: %v", err)
51	}
52
53	// Create SSA packages.
54	prog := ssautil.CreateProgram(iprog, 0)
55	prog.Build()
56
57	numPkgs := len(prog.AllPackages())
58	if want := 240; numPkgs < want {
59		t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
60	}
61
62	// Determine the set of packages/tests to analyze.
63	var mains []*ssa.Package
64	for _, info := range iprog.InitialPackages() {
65		ssapkg := prog.Package(info.Pkg)
66		if main := prog.CreateTestMainPackage(ssapkg); main != nil {
67			mains = append(mains, main)
68		}
69	}
70	if mains == nil {
71		t.Fatal("no tests found in analysis scope")
72	}
73
74	// Run the analysis.
75	config := &Config{
76		Reflection:     false, // TODO(adonovan): fix remaining bug in rVCallConstraint, then enable.
77		BuildCallGraph: true,
78		Mains:          mains,
79	}
80	// TODO(adonovan): add some query values (affects track bits).
81
82	t0 := time.Now()
83
84	result, err := Analyze(config)
85	if err != nil {
86		t.Fatal(err) // internal error in pointer analysis
87	}
88	_ = result // TODO(adonovan): measure something
89
90	t1 := time.Now()
91
92	// Dump some statistics.
93	allFuncs := ssautil.AllFunctions(prog)
94	var numInstrs int
95	for fn := range allFuncs {
96		for _, b := range fn.Blocks {
97			numInstrs += len(b.Instrs)
98		}
99	}
100
101	// determine line count
102	var lineCount int
103	prog.Fset.Iterate(func(f *token.File) bool {
104		lineCount += f.LineCount()
105		return true
106	})
107
108	t.Log("#Source lines:          ", lineCount)
109	t.Log("#Instructions:          ", numInstrs)
110	t.Log("Pointer analysis:       ", t1.Sub(t0))
111}
112