Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / cmd / structlayout / main.go
1 // structlayout displays the layout (field sizes and padding) of structs.
2 package main
3
4 import (
5         "encoding/json"
6         "flag"
7         "fmt"
8         "go/build"
9         "go/types"
10         "log"
11         "os"
12
13         "honnef.co/go/tools/gcsizes"
14         st "honnef.co/go/tools/structlayout"
15         "honnef.co/go/tools/version"
16
17         "golang.org/x/tools/go/loader"
18 )
19
20 var (
21         fJSON    bool
22         fVersion bool
23 )
24
25 func init() {
26         flag.BoolVar(&fJSON, "json", false, "Format data as JSON")
27         flag.BoolVar(&fVersion, "version", false, "Print version and exit")
28 }
29
30 func main() {
31         log.SetFlags(0)
32         flag.Parse()
33
34         if fVersion {
35                 version.Print()
36                 os.Exit(0)
37         }
38
39         if len(flag.Args()) != 2 {
40                 flag.Usage()
41                 os.Exit(1)
42         }
43
44         conf := loader.Config{
45                 Build: &build.Default,
46         }
47
48         var pkg string
49         var typName string
50         pkg = flag.Args()[0]
51         typName = flag.Args()[1]
52         conf.Import(pkg)
53
54         lprog, err := conf.Load()
55         if err != nil {
56                 log.Fatal(err)
57         }
58         var typ types.Type
59         obj := lprog.Package(pkg).Pkg.Scope().Lookup(typName)
60         if obj == nil {
61                 log.Fatal("couldn't find type")
62         }
63         typ = obj.Type()
64
65         st, ok := typ.Underlying().(*types.Struct)
66         if !ok {
67                 log.Fatal("identifier is not a struct type")
68         }
69
70         fields := sizes(st, typ.(*types.Named).Obj().Name(), 0, nil)
71         if fJSON {
72                 emitJSON(fields)
73         } else {
74                 emitText(fields)
75         }
76 }
77
78 func emitJSON(fields []st.Field) {
79         if fields == nil {
80                 fields = []st.Field{}
81         }
82         json.NewEncoder(os.Stdout).Encode(fields)
83 }
84
85 func emitText(fields []st.Field) {
86         for _, field := range fields {
87                 fmt.Println(field)
88         }
89 }
90 func sizes(typ *types.Struct, prefix string, base int64, out []st.Field) []st.Field {
91         s := gcsizes.ForArch(build.Default.GOARCH)
92         n := typ.NumFields()
93         var fields []*types.Var
94         for i := 0; i < n; i++ {
95                 fields = append(fields, typ.Field(i))
96         }
97         offsets := s.Offsetsof(fields)
98         for i := range offsets {
99                 offsets[i] += base
100         }
101
102         pos := base
103         for i, field := range fields {
104                 if offsets[i] > pos {
105                         padding := offsets[i] - pos
106                         out = append(out, st.Field{
107                                 IsPadding: true,
108                                 Start:     pos,
109                                 End:       pos + padding,
110                                 Size:      padding,
111                         })
112                         pos += padding
113                 }
114                 size := s.Sizeof(field.Type())
115                 if typ2, ok := field.Type().Underlying().(*types.Struct); ok && typ2.NumFields() != 0 {
116                         out = sizes(typ2, prefix+"."+field.Name(), pos, out)
117                 } else {
118                         out = append(out, st.Field{
119                                 Name:  prefix + "." + field.Name(),
120                                 Type:  field.Type().String(),
121                                 Start: offsets[i],
122                                 End:   offsets[i] + size,
123                                 Size:  size,
124                                 Align: s.Alignof(field.Type()),
125                         })
126                 }
127                 pos += size
128         }
129
130         if len(out) == 0 {
131                 return out
132         }
133         field := &out[len(out)-1]
134         if field.Size == 0 {
135                 field.Size = 1
136                 field.End++
137         }
138         pad := s.Sizeof(typ) - field.End
139         if pad > 0 {
140                 out = append(out, st.Field{
141                         IsPadding: true,
142                         Start:     field.End,
143                         End:       field.End + pad,
144                         Size:      pad,
145                 })
146         }
147
148         return out
149 }