name.go 3.9 KB

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