Skip to content

Commit 58c9a63

Browse files
adonovangopherbot
authored andcommitted
go/packages/internal/nodecount: count ast.Node frequency
This internal tool counts node frequencies, which may be useful when choosing type switch case order. It is also a nice illustration of packages.Load and ast.Inspect. Change-Id: I88c08987b6fe7b10e15f00844cd71fc850fc70c3 Reviewed-on: https://go-review.googlesource.com/c/tools/+/480915 Reviewed-by: Robert Findley <[email protected]> Run-TryBot: Alan Donovan <[email protected]> Auto-Submit: Alan Donovan <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 0a3e5f0 commit 58c9a63

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2023 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+
// The nodecount program illustrates the use of packages.Load to print
6+
// the frequency of occurrence of each type of syntax node among the
7+
// selected packages.
8+
//
9+
// Example usage:
10+
//
11+
// $ nodecount golang.org/x/tools/... std
12+
//
13+
// A typical distribution is 40% identifiers, 10% literals, 8%
14+
// selectors, and 6% calls; around 3% each of BinaryExpr, BlockStmt,
15+
// AssignStmt, Field, and Comment; and the rest accounting for 20%.
16+
package main
17+
18+
import (
19+
"flag"
20+
"fmt"
21+
"go/ast"
22+
"log"
23+
"reflect"
24+
"sort"
25+
26+
"golang.org/x/tools/go/packages"
27+
)
28+
29+
func main() {
30+
flag.Parse()
31+
32+
// Parse specified packages.
33+
config := packages.Config{
34+
Mode: packages.NeedSyntax | packages.NeedFiles,
35+
Tests: true,
36+
}
37+
pkgs, err := packages.Load(&config, flag.Args()...)
38+
if err != nil {
39+
log.Fatal(err)
40+
}
41+
42+
// Count each type of syntax node.
43+
var (
44+
byType = make(map[reflect.Type]int)
45+
total int
46+
)
47+
packages.Visit(pkgs, nil, func(p *packages.Package) {
48+
for _, f := range p.Syntax {
49+
ast.Inspect(f, func(n ast.Node) bool {
50+
if n != nil {
51+
byType[reflect.TypeOf(n)]++
52+
total++
53+
}
54+
return true
55+
})
56+
}
57+
})
58+
59+
// Print results (percent, count, type) in descending order.
60+
var types []reflect.Type
61+
for t := range byType {
62+
types = append(types, t)
63+
}
64+
sort.Slice(types, func(i, j int) bool {
65+
return byType[types[i]] > byType[types[j]]
66+
})
67+
for _, t := range types {
68+
percent := 100 * float64(byType[t]) / float64(total)
69+
fmt.Printf("%6.2f%%\t%8d\t%s\n", percent, byType[t], t)
70+
}
71+
}

0 commit comments

Comments
 (0)