| // 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" |
| |
| "golang.org/x/tools/go/loader" |
| ) |
| |
| //!+ |
| var bytesFlag = flag.Int("bytes", 48, "maximum parameter size in bytes") |
| |
| var sizeof = (&types.StdSizes{8, 8}).Sizeof // the sizeof function |
| |
| func PrintHugeParams(fset *token.FileSet, info *types.Info, files []*ast.File) { |
| checkTuple := func(descr string, tuple *types.Tuple) { |
| for i := 0; i < tuple.Len(); i++ { |
| v := tuple.At(i) |
| if sz := 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() |
| |
| // The loader loads a complete Go program from source code. |
| var conf loader.Config |
| _, err := conf.FromArgs(flag.Args(), false) |
| if err != nil { |
| log.Fatal(err) // command syntax error |
| } |
| lprog, err := conf.Load() |
| if err != nil { |
| log.Fatal(err) // load error |
| } |
| |
| for _, info := range lprog.InitialPackages() { |
| PrintHugeParams(lprog.Fset, &info.Info, info.Files) |
| } |
| } |
| |
| /* |
| //!+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 |
| */ |