golang.org/x/tools@v0.21.0/go/packages/internal/nodecount/nodecount.go (about)

     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  }