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