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