.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.1.1 / go / types / typeutil / util.go
1 package typeutil
2
3 import (
4         "bytes"
5         "go/types"
6         "sync"
7 )
8
9 var bufferPool = &sync.Pool{
10         New: func() interface{} {
11                 buf := bytes.NewBuffer(nil)
12                 buf.Grow(64)
13                 return buf
14         },
15 }
16
17 func FuncName(f *types.Func) string {
18         buf := bufferPool.Get().(*bytes.Buffer)
19         buf.Reset()
20         if f.Type() != nil {
21                 sig := f.Type().(*types.Signature)
22                 if recv := sig.Recv(); recv != nil {
23                         buf.WriteByte('(')
24                         if _, ok := recv.Type().(*types.Interface); ok {
25                                 // gcimporter creates abstract methods of
26                                 // named interfaces using the interface type
27                                 // (not the named type) as the receiver.
28                                 // Don't print it in full.
29                                 buf.WriteString("interface")
30                         } else {
31                                 types.WriteType(buf, recv.Type(), nil)
32                         }
33                         buf.WriteByte(')')
34                         buf.WriteByte('.')
35                 } else if f.Pkg() != nil {
36                         writePackage(buf, f.Pkg())
37                 }
38         }
39         buf.WriteString(f.Name())
40         s := buf.String()
41         bufferPool.Put(buf)
42         return s
43 }
44
45 func writePackage(buf *bytes.Buffer, pkg *types.Package) {
46         if pkg == nil {
47                 return
48         }
49         s := pkg.Path()
50         if s != "" {
51                 buf.WriteString(s)
52                 buf.WriteByte('.')
53         }
54 }
55
56 // Dereference returns a pointer's element type; otherwise it returns
57 // T.
58 func Dereference(T types.Type) types.Type {
59         if p, ok := T.Underlying().(*types.Pointer); ok {
60                 return p.Elem()
61         }
62         return T
63 }
64
65 // DereferenceR returns a pointer's element type; otherwise it returns
66 // T. If the element type is itself a pointer, DereferenceR will be
67 // applied recursively.
68 func DereferenceR(T types.Type) types.Type {
69         if p, ok := T.Underlying().(*types.Pointer); ok {
70                 return DereferenceR(p.Elem())
71         }
72         return T
73 }
74
75 func IsObject(obj types.Object, name string) bool {
76         var path string
77         if pkg := obj.Pkg(); pkg != nil {
78                 path = pkg.Path() + "."
79         }
80         return path+obj.Name() == name
81 }
82
83 // OPT(dh): IsType is kind of expensive; should we really use it?
84 func IsType(T types.Type, name string) bool { return types.TypeString(T, nil) == name }
85
86 func IsPointerLike(T types.Type) bool {
87         switch T := T.Underlying().(type) {
88         case *types.Interface, *types.Chan, *types.Map, *types.Signature, *types.Pointer, *types.Slice:
89                 return true
90         case *types.Basic:
91                 return T.Kind() == types.UnsafePointer
92         }
93         return false
94 }
95
96 type Field struct {
97         Var  *types.Var
98         Tag  string
99         Path []int
100 }
101
102 // FlattenFields recursively flattens T and embedded structs,
103 // returning a list of fields. If multiple fields with the same name
104 // exist, all will be returned.
105 func FlattenFields(T *types.Struct) []Field {
106         return flattenFields(T, nil, nil)
107 }
108
109 func flattenFields(T *types.Struct, path []int, seen map[types.Type]bool) []Field {
110         if seen == nil {
111                 seen = map[types.Type]bool{}
112         }
113         if seen[T] {
114                 return nil
115         }
116         seen[T] = true
117         var out []Field
118         for i := 0; i < T.NumFields(); i++ {
119                 field := T.Field(i)
120                 tag := T.Tag(i)
121                 np := append(path[:len(path):len(path)], i)
122                 if field.Anonymous() {
123                         if s, ok := Dereference(field.Type()).Underlying().(*types.Struct); ok {
124                                 out = append(out, flattenFields(s, np, seen)...)
125                         }
126                 } else {
127                         out = append(out, Field{field, tag, np})
128                 }
129         }
130         return out
131 }