// +build ignore,OMIT package main import ( "fmt" "go/ast" "go/parser" "go/token" "io/ioutil" "path/filepath" "runtime" "sort" "strings" "time" ) func walk(dir string, f func(string) bool) bool { fis, err := ioutil.ReadDir(dir) if err != nil { panic(err) } // parse all *.go files in directory; // traverse subdirectories, but don't walk into testdata for _, fi := range fis { path := filepath.Join(dir, fi.Name()) if fi.IsDir() { if fi.Name() != "testdata" { if !walk(path, f) { return false } } } else if strings.HasSuffix(fi.Name(), ".go") && !strings.HasPrefix(fi.Name(), ".") { if !f(path) { return false } } } return true } func walkStdLib(f func(filename string) bool) { walk(filepath.Join(runtime.GOROOT(), "src"), f) } type histogram map[string]int func (h histogram) add(filename string) { f, err := parser.ParseFile(token.NewFileSet(), filename, nil, 0) if err != nil { panic(err) } ast.Inspect(f, func(n ast.Node) bool { if n, ok := n.(ast.Stmt); ok { h[fmt.Sprintf("%T", n)]++ } return true }) } // print START OMIT func (h histogram) print() { var list []entry var total int for key, count := range h { list = append(list, entry{key, count}) total += count } sort.Sort(byCount(list)) percent := 100 / float64(total) for i, e := range list { fmt.Printf("%4d. %5.2f%% %5d %s\n", i, float64(e.count)*percent, e.count, e.key) } } // print END OMIT // byCount START OMIT type entry struct { key string count int } type byCount []entry func (s byCount) Len() int { return len(s) } func (s byCount) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s byCount) Less(i, j int) bool { x, y := s[i], s[j] if x.count != y.count { return x.count > y.count // want larger count first } return x.key < y.key } // byCount END OMIT // main START OMIT func main() { start := time.Now() h := make(histogram) walkStdLib(func(filename string) bool { h.add(filename) return true }) h.print() fmt.Println(time.Since(start)) } // main END OMIT