.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.1.1 / 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/go/gcsizes"
14         "honnef.co/go/tools/lintcmd/version"
15         st "honnef.co/go/tools/structlayout"
16
17         "golang.org/x/tools/go/packages"
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         cfg := &packages.Config{
45                 Mode:  packages.NeedImports | packages.NeedExportsFile | packages.NeedTypes | packages.NeedSyntax,
46                 Tests: true,
47         }
48         pkgs, err := packages.Load(cfg, flag.Args()[0])
49         if err != nil {
50                 log.Fatal(err)
51         }
52
53         for _, pkg := range pkgs {
54                 typName := flag.Args()[1]
55
56                 var typ types.Type
57                 obj := pkg.Types.Scope().Lookup(typName)
58                 if obj == nil {
59                         continue
60                 }
61                 typ = obj.Type()
62
63                 st, ok := typ.Underlying().(*types.Struct)
64                 if !ok {
65                         log.Fatal("identifier is not a struct type")
66                 }
67
68                 fields := sizes(st, typ.(*types.Named).Obj().Name(), 0, nil)
69                 if fJSON {
70                         emitJSON(fields)
71                 } else {
72                         emitText(fields)
73                 }
74                 return
75         }
76
77         log.Fatal("couldn't find type")
78 }
79
80 func emitJSON(fields []st.Field) {
81         if fields == nil {
82                 fields = []st.Field{}
83         }
84         json.NewEncoder(os.Stdout).Encode(fields)
85 }
86
87 func emitText(fields []st.Field) {
88         for _, field := range fields {
89                 fmt.Println(field)
90         }
91 }
92 func sizes(typ *types.Struct, prefix string, base int64, out []st.Field) []st.Field {
93         s := gcsizes.ForArch(build.Default.GOARCH)
94         n := typ.NumFields()
95         var fields []*types.Var
96         for i := 0; i < n; i++ {
97                 fields = append(fields, typ.Field(i))
98         }
99         offsets := s.Offsetsof(fields)
100         for i := range offsets {
101                 offsets[i] += base
102         }
103
104         pos := base
105         for i, field := range fields {
106                 if offsets[i] > pos {
107                         padding := offsets[i] - pos
108                         out = append(out, st.Field{
109                                 IsPadding: true,
110                                 Start:     pos,
111                                 End:       pos + padding,
112                                 Size:      padding,
113                         })
114                         pos += padding
115                 }
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)
119                 } else {
120                         out = append(out, st.Field{
121                                 Name:  prefix + "." + field.Name(),
122                                 Type:  field.Type().String(),
123                                 Start: offsets[i],
124                                 End:   offsets[i] + size,
125                                 Size:  size,
126                                 Align: s.Alignof(field.Type()),
127                         })
128                 }
129                 pos += size
130         }
131
132         if len(out) == 0 {
133                 return out
134         }
135         field := &out[len(out)-1]
136         if field.Size == 0 {
137                 field.Size = 1
138                 field.End++
139         }
140         pad := s.Sizeof(typ) - field.End
141         if pad > 0 {
142                 out = append(out, st.Field{
143                         IsPadding: true,
144                         Start:     field.End,
145                         End:       field.End + pad,
146                         Size:      pad,
147                 })
148         }
149
150         return out
151 }