| // The hugeparam command identifies by-value parameters that are larger than n bytes. |
| // |
| // Example: |
| // |
| // $ ./hugeparams encoding/xml |
| package main |
| |
| import ( |
| "flag" |
| "fmt" |
| "go/ast" |
| "go/token" |
| "go/types" |
| "log" |
| "os" |
| |
| "golang.org/x/tools/go/packages" |
| ) |
| |
| // !+ |
| var bytesFlag = flag.Int("bytes", 48, "maximum parameter size in bytes") |
| |
| func PrintHugeParams(fset *token.FileSet, info *types.Info, sizes types.Sizes, files []*ast.File) { |
| checkTuple := func(descr string, tuple *types.Tuple) { |
| for i := 0; i < tuple.Len(); i++ { |
| v := tuple.At(i) |
| if sz := sizes.Sizeof(v.Type()); sz > int64(*bytesFlag) { |
| fmt.Printf("%s: %q %s: %s = %d bytes\n", |
| fset.Position(v.Pos()), |
| v.Name(), descr, v.Type(), sz) |
| } |
| } |
| } |
| checkSig := func(sig *types.Signature) { |
| checkTuple("parameter", sig.Params()) |
| checkTuple("result", sig.Results()) |
| } |
| for _, file := range files { |
| ast.Inspect(file, func(n ast.Node) bool { |
| switch n := n.(type) { |
| case *ast.FuncDecl: |
| checkSig(info.Defs[n.Name].Type().(*types.Signature)) |
| case *ast.FuncLit: |
| checkSig(info.Types[n.Type].Type.(*types.Signature)) |
| } |
| return true |
| }) |
| } |
| } |
| |
| //!- |
| |
| func main() { |
| flag.Parse() |
| |
| // Load complete type information for the specified packages, |
| // along with type-annotated syntax and the "sizeof" function. |
| // Types for dependencies are loaded from export data. |
| conf := &packages.Config{Mode: packages.LoadSyntax} |
| pkgs, err := packages.Load(conf, flag.Args()...) |
| if err != nil { |
| log.Fatal(err) // failed to load anything |
| } |
| if packages.PrintErrors(pkgs) > 0 { |
| os.Exit(1) // some packages contained errors |
| } |
| |
| for _, pkg := range pkgs { |
| PrintHugeParams(pkg.Fset, pkg.TypesInfo, pkg.TypesSizes, pkg.Syntax) |
| } |
| } |
| |
| /* |
| //!+output |
| % ./hugeparam encoding/xml |
| /go/src/encoding/xml/marshal.go:167:50: "start" parameter: encoding/xml.StartElement = 56 bytes |
| /go/src/encoding/xml/marshal.go:734:97: "" result: encoding/xml.StartElement = 56 bytes |
| /go/src/encoding/xml/marshal.go:761:51: "start" parameter: encoding/xml.StartElement = 56 bytes |
| /go/src/encoding/xml/marshal.go:781:68: "start" parameter: encoding/xml.StartElement = 56 bytes |
| /go/src/encoding/xml/xml.go:72:30: "" result: encoding/xml.StartElement = 56 bytes |
| //!-output |
| */ |