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 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} 158