blob: b6c12cefb47e67ec457a1b4beabd4a26d0d929dd [file] [log] [blame]
David K. Bainbridgec415efe2021-08-19 13:05:21 +00001// Copyright 2020, 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
5package value
6
7import (
8 "reflect"
9 "strconv"
10)
11
12// TypeString is nearly identical to reflect.Type.String,
13// but has an additional option to specify that full type names be used.
14func TypeString(t reflect.Type, qualified bool) string {
15 return string(appendTypeName(nil, t, qualified, false))
16}
17
18func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte {
19 // BUG: Go reflection provides no way to disambiguate two named types
20 // of the same name and within the same package,
21 // but declared within the namespace of different functions.
22
23 // Named type.
24 if t.Name() != "" {
25 if qualified && t.PkgPath() != "" {
26 b = append(b, '"')
27 b = append(b, t.PkgPath()...)
28 b = append(b, '"')
29 b = append(b, '.')
30 b = append(b, t.Name()...)
31 } else {
32 b = append(b, t.String()...)
33 }
34 return b
35 }
36
37 // Unnamed type.
38 switch k := t.Kind(); k {
39 case reflect.Bool, reflect.String, reflect.UnsafePointer,
40 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
41 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
42 reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
43 b = append(b, k.String()...)
44 case reflect.Chan:
45 if t.ChanDir() == reflect.RecvDir {
46 b = append(b, "<-"...)
47 }
48 b = append(b, "chan"...)
49 if t.ChanDir() == reflect.SendDir {
50 b = append(b, "<-"...)
51 }
52 b = append(b, ' ')
53 b = appendTypeName(b, t.Elem(), qualified, false)
54 case reflect.Func:
55 if !elideFunc {
56 b = append(b, "func"...)
57 }
58 b = append(b, '(')
59 for i := 0; i < t.NumIn(); i++ {
60 if i > 0 {
61 b = append(b, ", "...)
62 }
63 if i == t.NumIn()-1 && t.IsVariadic() {
64 b = append(b, "..."...)
65 b = appendTypeName(b, t.In(i).Elem(), qualified, false)
66 } else {
67 b = appendTypeName(b, t.In(i), qualified, false)
68 }
69 }
70 b = append(b, ')')
71 switch t.NumOut() {
72 case 0:
73 // Do nothing
74 case 1:
75 b = append(b, ' ')
76 b = appendTypeName(b, t.Out(0), qualified, false)
77 default:
78 b = append(b, " ("...)
79 for i := 0; i < t.NumOut(); i++ {
80 if i > 0 {
81 b = append(b, ", "...)
82 }
83 b = appendTypeName(b, t.Out(i), qualified, false)
84 }
85 b = append(b, ')')
86 }
87 case reflect.Struct:
88 b = append(b, "struct{ "...)
89 for i := 0; i < t.NumField(); i++ {
90 if i > 0 {
91 b = append(b, "; "...)
92 }
93 sf := t.Field(i)
94 if !sf.Anonymous {
95 if qualified && sf.PkgPath != "" {
96 b = append(b, '"')
97 b = append(b, sf.PkgPath...)
98 b = append(b, '"')
99 b = append(b, '.')
100 }
101 b = append(b, sf.Name...)
102 b = append(b, ' ')
103 }
104 b = appendTypeName(b, sf.Type, qualified, false)
105 if sf.Tag != "" {
106 b = append(b, ' ')
107 b = strconv.AppendQuote(b, string(sf.Tag))
108 }
109 }
110 if b[len(b)-1] == ' ' {
111 b = b[:len(b)-1]
112 } else {
113 b = append(b, ' ')
114 }
115 b = append(b, '}')
116 case reflect.Slice, reflect.Array:
117 b = append(b, '[')
118 if k == reflect.Array {
119 b = strconv.AppendUint(b, uint64(t.Len()), 10)
120 }
121 b = append(b, ']')
122 b = appendTypeName(b, t.Elem(), qualified, false)
123 case reflect.Map:
124 b = append(b, "map["...)
125 b = appendTypeName(b, t.Key(), qualified, false)
126 b = append(b, ']')
127 b = appendTypeName(b, t.Elem(), qualified, false)
128 case reflect.Ptr:
129 b = append(b, '*')
130 b = appendTypeName(b, t.Elem(), qualified, false)
131 case reflect.Interface:
132 b = append(b, "interface{ "...)
133 for i := 0; i < t.NumMethod(); i++ {
134 if i > 0 {
135 b = append(b, "; "...)
136 }
137 m := t.Method(i)
138 if qualified && m.PkgPath != "" {
139 b = append(b, '"')
140 b = append(b, m.PkgPath...)
141 b = append(b, '"')
142 b = append(b, '.')
143 }
144 b = append(b, m.Name...)
145 b = appendTypeName(b, m.Type, qualified, true)
146 }
147 if b[len(b)-1] == ' ' {
148 b = b[:len(b)-1]
149 } else {
150 b = append(b, ' ')
151 }
152 b = append(b, '}')
153 default:
154 panic("invalid kind: " + k.String())
155 }
156 return b
157}