Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / cmd / godex / print.go
1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package main
6
7 import (
8         "bytes"
9         "fmt"
10         "go/constant"
11         "go/token"
12         "go/types"
13         "io"
14         "math/big"
15 )
16
17 // TODO(gri) use tabwriter for alignment?
18
19 func print(w io.Writer, pkg *types.Package, filter func(types.Object) bool) {
20         var p printer
21         p.pkg = pkg
22         p.printPackage(pkg, filter)
23         p.printGccgoExtra(pkg)
24         io.Copy(w, &p.buf)
25 }
26
27 type printer struct {
28         pkg    *types.Package
29         buf    bytes.Buffer
30         indent int  // current indentation level
31         last   byte // last byte written
32 }
33
34 func (p *printer) print(s string) {
35         // Write the string one byte at a time. We care about the presence of
36         // newlines for indentation which we will see even in the presence of
37         // (non-corrupted) Unicode; no need to read one rune at a time.
38         for i := 0; i < len(s); i++ {
39                 ch := s[i]
40                 if ch != '\n' && p.last == '\n' {
41                         // Note: This could lead to a range overflow for very large
42                         // indentations, but it's extremely unlikely to happen for
43                         // non-pathological code.
44                         p.buf.WriteString("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"[:p.indent])
45                 }
46                 p.buf.WriteByte(ch)
47                 p.last = ch
48         }
49 }
50
51 func (p *printer) printf(format string, args ...interface{}) {
52         p.print(fmt.Sprintf(format, args...))
53 }
54
55 // methodsFor returns the named type and corresponding methods if the type
56 // denoted by obj is not an interface and has methods. Otherwise it returns
57 // the zero value.
58 func methodsFor(obj *types.TypeName) (*types.Named, []*types.Selection) {
59         named, _ := obj.Type().(*types.Named)
60         if named == nil {
61                 // A type name's type can also be the
62                 // exported basic type unsafe.Pointer.
63                 return nil, nil
64         }
65         if _, ok := named.Underlying().(*types.Interface); ok {
66                 // ignore interfaces
67                 return nil, nil
68         }
69         methods := combinedMethodSet(named)
70         if len(methods) == 0 {
71                 return nil, nil
72         }
73         return named, methods
74 }
75
76 func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) {
77         // collect objects by kind
78         var (
79                 consts   []*types.Const
80                 typem    []*types.Named    // non-interface types with methods
81                 typez    []*types.TypeName // interfaces or types without methods
82                 vars     []*types.Var
83                 funcs    []*types.Func
84                 builtins []*types.Builtin
85                 methods  = make(map[*types.Named][]*types.Selection) // method sets for named types
86         )
87         scope := pkg.Scope()
88         for _, name := range scope.Names() {
89                 obj := scope.Lookup(name)
90                 if obj.Exported() {
91                         // collect top-level exported and possibly filtered objects
92                         if filter == nil || filter(obj) {
93                                 switch obj := obj.(type) {
94                                 case *types.Const:
95                                         consts = append(consts, obj)
96                                 case *types.TypeName:
97                                         // group into types with methods and types without
98                                         if named, m := methodsFor(obj); named != nil {
99                                                 typem = append(typem, named)
100                                                 methods[named] = m
101                                         } else {
102                                                 typez = append(typez, obj)
103                                         }
104                                 case *types.Var:
105                                         vars = append(vars, obj)
106                                 case *types.Func:
107                                         funcs = append(funcs, obj)
108                                 case *types.Builtin:
109                                         // for unsafe.Sizeof, etc.
110                                         builtins = append(builtins, obj)
111                                 }
112                         }
113                 } else if filter == nil {
114                         // no filtering: collect top-level unexported types with methods
115                         if obj, _ := obj.(*types.TypeName); obj != nil {
116                                 // see case *types.TypeName above
117                                 if named, m := methodsFor(obj); named != nil {
118                                         typem = append(typem, named)
119                                         methods[named] = m
120                                 }
121                         }
122                 }
123         }
124
125         p.printf("package %s  // %q\n", pkg.Name(), pkg.Path())
126
127         p.printDecl("const", len(consts), func() {
128                 for _, obj := range consts {
129                         p.printObj(obj)
130                         p.print("\n")
131                 }
132         })
133
134         p.printDecl("var", len(vars), func() {
135                 for _, obj := range vars {
136                         p.printObj(obj)
137                         p.print("\n")
138                 }
139         })
140
141         p.printDecl("type", len(typez), func() {
142                 for _, obj := range typez {
143                         p.printf("%s ", obj.Name())
144                         typ := obj.Type()
145                         if isAlias(obj) {
146                                 p.print("= ")
147                                 p.writeType(p.pkg, typ)
148                         } else {
149                                 p.writeType(p.pkg, typ.Underlying())
150                         }
151                         p.print("\n")
152                 }
153         })
154
155         // non-interface types with methods
156         for _, named := range typem {
157                 first := true
158                 if obj := named.Obj(); obj.Exported() {
159                         if first {
160                                 p.print("\n")
161                                 first = false
162                         }
163                         p.printf("type %s ", obj.Name())
164                         p.writeType(p.pkg, named.Underlying())
165                         p.print("\n")
166                 }
167                 for _, m := range methods[named] {
168                         if obj := m.Obj(); obj.Exported() {
169                                 if first {
170                                         p.print("\n")
171                                         first = false
172                                 }
173                                 p.printFunc(m.Recv(), obj.(*types.Func))
174                                 p.print("\n")
175                         }
176                 }
177         }
178
179         if len(funcs) > 0 {
180                 p.print("\n")
181                 for _, obj := range funcs {
182                         p.printFunc(nil, obj)
183                         p.print("\n")
184                 }
185         }
186
187         // TODO(gri) better handling of builtins (package unsafe only)
188         if len(builtins) > 0 {
189                 p.print("\n")
190                 for _, obj := range builtins {
191                         p.printf("func %s() // builtin\n", obj.Name())
192                 }
193         }
194
195         p.print("\n")
196 }
197
198 func (p *printer) printDecl(keyword string, n int, printGroup func()) {
199         switch n {
200         case 0:
201                 // nothing to do
202         case 1:
203                 p.printf("\n%s ", keyword)
204                 printGroup()
205         default:
206                 p.printf("\n%s (\n", keyword)
207                 p.indent++
208                 printGroup()
209                 p.indent--
210                 p.print(")\n")
211         }
212 }
213
214 // absInt returns the absolute value of v as a *big.Int.
215 // v must be a numeric value.
216 func absInt(v constant.Value) *big.Int {
217         // compute big-endian representation of v
218         b := constant.Bytes(v) // little-endian
219         for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
220                 b[i], b[j] = b[j], b[i]
221         }
222         return new(big.Int).SetBytes(b)
223 }
224
225 var (
226         one = big.NewRat(1, 1)
227         ten = big.NewRat(10, 1)
228 )
229
230 // floatString returns the string representation for a
231 // numeric value v in normalized floating-point format.
232 func floatString(v constant.Value) string {
233         if constant.Sign(v) == 0 {
234                 return "0.0"
235         }
236         // x != 0
237
238         // convert |v| into a big.Rat x
239         x := new(big.Rat).SetFrac(absInt(constant.Num(v)), absInt(constant.Denom(v)))
240
241         // normalize x and determine exponent e
242         // (This is not very efficient, but also not speed-critical.)
243         var e int
244         for x.Cmp(ten) >= 0 {
245                 x.Quo(x, ten)
246                 e++
247         }
248         for x.Cmp(one) < 0 {
249                 x.Mul(x, ten)
250                 e--
251         }
252
253         // TODO(gri) Values such as 1/2 are easier to read in form 0.5
254         // rather than 5.0e-1. Similarly, 1.0e1 is easier to read as
255         // 10.0. Fine-tune best exponent range for readability.
256
257         s := x.FloatString(100) // good-enough precision
258
259         // trim trailing 0's
260         i := len(s)
261         for i > 0 && s[i-1] == '0' {
262                 i--
263         }
264         s = s[:i]
265
266         // add a 0 if the number ends in decimal point
267         if len(s) > 0 && s[len(s)-1] == '.' {
268                 s += "0"
269         }
270
271         // add exponent and sign
272         if e != 0 {
273                 s += fmt.Sprintf("e%+d", e)
274         }
275         if constant.Sign(v) < 0 {
276                 s = "-" + s
277         }
278
279         // TODO(gri) If v is a "small" fraction (i.e., numerator and denominator
280         // are just a small number of decimal digits), add the exact fraction as
281         // a comment. For instance: 3.3333...e-1 /* = 1/3 */
282
283         return s
284 }
285
286 // valString returns the string representation for the value v.
287 // Setting floatFmt forces an integer value to be formatted in
288 // normalized floating-point format.
289 // TODO(gri) Move this code into package constant.
290 func valString(v constant.Value, floatFmt bool) string {
291         switch v.Kind() {
292         case constant.Int:
293                 if floatFmt {
294                         return floatString(v)
295                 }
296         case constant.Float:
297                 return floatString(v)
298         case constant.Complex:
299                 re := constant.Real(v)
300                 im := constant.Imag(v)
301                 var s string
302                 if constant.Sign(re) != 0 {
303                         s = floatString(re)
304                         if constant.Sign(im) >= 0 {
305                                 s += " + "
306                         } else {
307                                 s += " - "
308                                 im = constant.UnaryOp(token.SUB, im, 0) // negate im
309                         }
310                 }
311                 // im != 0, otherwise v would be constant.Int or constant.Float
312                 return s + floatString(im) + "i"
313         }
314         return v.String()
315 }
316
317 func (p *printer) printObj(obj types.Object) {
318         p.print(obj.Name())
319
320         typ, basic := obj.Type().Underlying().(*types.Basic)
321         if basic && typ.Info()&types.IsUntyped != 0 {
322                 // don't write untyped types
323         } else {
324                 p.print(" ")
325                 p.writeType(p.pkg, obj.Type())
326         }
327
328         if obj, ok := obj.(*types.Const); ok {
329                 floatFmt := basic && typ.Info()&(types.IsFloat|types.IsComplex) != 0
330                 p.print(" = ")
331                 p.print(valString(obj.Val(), floatFmt))
332         }
333 }
334
335 func (p *printer) printFunc(recvType types.Type, obj *types.Func) {
336         p.print("func ")
337         sig := obj.Type().(*types.Signature)
338         if recvType != nil {
339                 p.print("(")
340                 p.writeType(p.pkg, recvType)
341                 p.print(") ")
342         }
343         p.print(obj.Name())
344         p.writeSignature(p.pkg, sig)
345 }
346
347 // combinedMethodSet returns the method set for a named type T
348 // merged with all the methods of *T that have different names than
349 // the methods of T.
350 //
351 // combinedMethodSet is analogous to types/typeutil.IntuitiveMethodSet
352 // but doesn't require a MethodSetCache.
353 // TODO(gri) If this functionality doesn't change over time, consider
354 // just calling IntuitiveMethodSet eventually.
355 func combinedMethodSet(T *types.Named) []*types.Selection {
356         // method set for T
357         mset := types.NewMethodSet(T)
358         var res []*types.Selection
359         for i, n := 0, mset.Len(); i < n; i++ {
360                 res = append(res, mset.At(i))
361         }
362
363         // add all *T methods with names different from T methods
364         pmset := types.NewMethodSet(types.NewPointer(T))
365         for i, n := 0, pmset.Len(); i < n; i++ {
366                 pm := pmset.At(i)
367                 if obj := pm.Obj(); mset.Lookup(obj.Pkg(), obj.Name()) == nil {
368                         res = append(res, pm)
369                 }
370         }
371
372         return res
373 }