1 // structlayout displays the layout (field sizes and padding) of structs.
13 "honnef.co/go/tools/go/gcsizes"
14 "honnef.co/go/tools/lintcmd/version"
15 st "honnef.co/go/tools/structlayout"
17 "golang.org/x/tools/go/packages"
26 flag.BoolVar(&fJSON, "json", false, "Format data as JSON")
27 flag.BoolVar(&fVersion, "version", false, "Print version and exit")
39 if len(flag.Args()) != 2 {
44 cfg := &packages.Config{
45 Mode: packages.NeedImports | packages.NeedExportsFile | packages.NeedTypes | packages.NeedSyntax,
48 pkgs, err := packages.Load(cfg, flag.Args()[0])
53 for _, pkg := range pkgs {
54 typName := flag.Args()[1]
57 obj := pkg.Types.Scope().Lookup(typName)
63 st, ok := typ.Underlying().(*types.Struct)
65 log.Fatal("identifier is not a struct type")
68 fields := sizes(st, typ.(*types.Named).Obj().Name(), 0, nil)
77 log.Fatal("couldn't find type")
80 func emitJSON(fields []st.Field) {
84 json.NewEncoder(os.Stdout).Encode(fields)
87 func emitText(fields []st.Field) {
88 for _, field := range fields {
92 func sizes(typ *types.Struct, prefix string, base int64, out []st.Field) []st.Field {
93 s := gcsizes.ForArch(build.Default.GOARCH)
95 var fields []*types.Var
96 for i := 0; i < n; i++ {
97 fields = append(fields, typ.Field(i))
99 offsets := s.Offsetsof(fields)
100 for i := range offsets {
105 for i, field := range fields {
106 if offsets[i] > pos {
107 padding := offsets[i] - pos
108 out = append(out, st.Field{
116 size := s.Sizeof(field.Type())
117 if typ2, ok := field.Type().Underlying().(*types.Struct); ok && typ2.NumFields() != 0 {
118 out = sizes(typ2, prefix+"."+field.Name(), pos, out)
120 out = append(out, st.Field{
121 Name: prefix + "." + field.Name(),
122 Type: field.Type().String(),
124 End: offsets[i] + size,
126 Align: s.Alignof(field.Type()),
135 field := &out[len(out)-1]
140 pad := s.Sizeof(typ) - field.End
142 out = append(out, st.Field{
145 End: field.End + pad,