model.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. // Copyright 2012 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Package model contains the data model necessary for generating mock implementations.
  15. package model
  16. import (
  17. "encoding/gob"
  18. "fmt"
  19. "io"
  20. "reflect"
  21. "strings"
  22. )
  23. // pkgPath is the importable path for package model
  24. const pkgPath = "github.com/golang/mock/mockgen/model"
  25. // Package is a Go package. It may be a subset.
  26. type Package struct {
  27. Name string
  28. Interfaces []*Interface
  29. DotImports []string
  30. }
  31. func (pkg *Package) Print(w io.Writer) {
  32. fmt.Fprintf(w, "package %s\n", pkg.Name)
  33. for _, intf := range pkg.Interfaces {
  34. intf.Print(w)
  35. }
  36. }
  37. // Imports returns the imports needed by the Package as a set of import paths.
  38. func (pkg *Package) Imports() map[string]bool {
  39. im := make(map[string]bool)
  40. for _, intf := range pkg.Interfaces {
  41. intf.addImports(im)
  42. }
  43. return im
  44. }
  45. // Interface is a Go interface.
  46. type Interface struct {
  47. Name string
  48. Methods []*Method
  49. }
  50. func (intf *Interface) Print(w io.Writer) {
  51. fmt.Fprintf(w, "interface %s\n", intf.Name)
  52. for _, m := range intf.Methods {
  53. m.Print(w)
  54. }
  55. }
  56. func (intf *Interface) addImports(im map[string]bool) {
  57. for _, m := range intf.Methods {
  58. m.addImports(im)
  59. }
  60. }
  61. // Method is a single method of an interface.
  62. type Method struct {
  63. Name string
  64. In, Out []*Parameter
  65. Variadic *Parameter // may be nil
  66. }
  67. func (m *Method) Print(w io.Writer) {
  68. fmt.Fprintf(w, " - method %s\n", m.Name)
  69. if len(m.In) > 0 {
  70. fmt.Fprintf(w, " in:\n")
  71. for _, p := range m.In {
  72. p.Print(w)
  73. }
  74. }
  75. if m.Variadic != nil {
  76. fmt.Fprintf(w, " ...:\n")
  77. m.Variadic.Print(w)
  78. }
  79. if len(m.Out) > 0 {
  80. fmt.Fprintf(w, " out:\n")
  81. for _, p := range m.Out {
  82. p.Print(w)
  83. }
  84. }
  85. }
  86. func (m *Method) addImports(im map[string]bool) {
  87. for _, p := range m.In {
  88. p.Type.addImports(im)
  89. }
  90. if m.Variadic != nil {
  91. m.Variadic.Type.addImports(im)
  92. }
  93. for _, p := range m.Out {
  94. p.Type.addImports(im)
  95. }
  96. }
  97. // Parameter is an argument or return parameter of a method.
  98. type Parameter struct {
  99. Name string // may be empty
  100. Type Type
  101. }
  102. func (p *Parameter) Print(w io.Writer) {
  103. n := p.Name
  104. if n == "" {
  105. n = `""`
  106. }
  107. fmt.Fprintf(w, " - %v: %v\n", n, p.Type.String(nil, ""))
  108. }
  109. // Type is a Go type.
  110. type Type interface {
  111. String(pm map[string]string, pkgOverride string) string
  112. addImports(im map[string]bool)
  113. }
  114. func init() {
  115. gob.Register(&ArrayType{})
  116. gob.Register(&ChanType{})
  117. gob.Register(&FuncType{})
  118. gob.Register(&MapType{})
  119. gob.Register(&NamedType{})
  120. gob.Register(&PointerType{})
  121. // Call gob.RegisterName to make sure it has the consistent name registered
  122. // for both gob decoder and encoder.
  123. //
  124. // For a non-pointer type, gob.Register will try to get package full path by
  125. // calling rt.PkgPath() for a name to register. If your project has vendor
  126. // directory, it is possible that PkgPath will get a path like this:
  127. // ../../../vendor/github.com/golang/mock/mockgen/model
  128. gob.RegisterName(pkgPath+".PredeclaredType", PredeclaredType(""))
  129. }
  130. // ArrayType is an array or slice type.
  131. type ArrayType struct {
  132. Len int // -1 for slices, >= 0 for arrays
  133. Type Type
  134. }
  135. func (at *ArrayType) String(pm map[string]string, pkgOverride string) string {
  136. s := "[]"
  137. if at.Len > -1 {
  138. s = fmt.Sprintf("[%d]", at.Len)
  139. }
  140. return s + at.Type.String(pm, pkgOverride)
  141. }
  142. func (at *ArrayType) addImports(im map[string]bool) { at.Type.addImports(im) }
  143. // ChanType is a channel type.
  144. type ChanType struct {
  145. Dir ChanDir // 0, 1 or 2
  146. Type Type
  147. }
  148. func (ct *ChanType) String(pm map[string]string, pkgOverride string) string {
  149. s := ct.Type.String(pm, pkgOverride)
  150. if ct.Dir == RecvDir {
  151. return "<-chan " + s
  152. }
  153. if ct.Dir == SendDir {
  154. return "chan<- " + s
  155. }
  156. return "chan " + s
  157. }
  158. func (ct *ChanType) addImports(im map[string]bool) { ct.Type.addImports(im) }
  159. // ChanDir is a channel direction.
  160. type ChanDir int
  161. const (
  162. RecvDir ChanDir = 1
  163. SendDir ChanDir = 2
  164. )
  165. // FuncType is a function type.
  166. type FuncType struct {
  167. In, Out []*Parameter
  168. Variadic *Parameter // may be nil
  169. }
  170. func (ft *FuncType) String(pm map[string]string, pkgOverride string) string {
  171. args := make([]string, len(ft.In))
  172. for i, p := range ft.In {
  173. args[i] = p.Type.String(pm, pkgOverride)
  174. }
  175. if ft.Variadic != nil {
  176. args = append(args, "..."+ft.Variadic.Type.String(pm, pkgOverride))
  177. }
  178. rets := make([]string, len(ft.Out))
  179. for i, p := range ft.Out {
  180. rets[i] = p.Type.String(pm, pkgOverride)
  181. }
  182. retString := strings.Join(rets, ", ")
  183. if nOut := len(ft.Out); nOut == 1 {
  184. retString = " " + retString
  185. } else if nOut > 1 {
  186. retString = " (" + retString + ")"
  187. }
  188. return "func(" + strings.Join(args, ", ") + ")" + retString
  189. }
  190. func (ft *FuncType) addImports(im map[string]bool) {
  191. for _, p := range ft.In {
  192. p.Type.addImports(im)
  193. }
  194. if ft.Variadic != nil {
  195. ft.Variadic.Type.addImports(im)
  196. }
  197. for _, p := range ft.Out {
  198. p.Type.addImports(im)
  199. }
  200. }
  201. // MapType is a map type.
  202. type MapType struct {
  203. Key, Value Type
  204. }
  205. func (mt *MapType) String(pm map[string]string, pkgOverride string) string {
  206. return "map[" + mt.Key.String(pm, pkgOverride) + "]" + mt.Value.String(pm, pkgOverride)
  207. }
  208. func (mt *MapType) addImports(im map[string]bool) {
  209. mt.Key.addImports(im)
  210. mt.Value.addImports(im)
  211. }
  212. // NamedType is an exported type in a package.
  213. type NamedType struct {
  214. Package string // may be empty
  215. Type string // TODO: should this be typed Type?
  216. }
  217. func (nt *NamedType) String(pm map[string]string, pkgOverride string) string {
  218. // TODO: is this right?
  219. if pkgOverride == nt.Package {
  220. return nt.Type
  221. }
  222. return pm[nt.Package] + "." + nt.Type
  223. }
  224. func (nt *NamedType) addImports(im map[string]bool) {
  225. if nt.Package != "" {
  226. im[nt.Package] = true
  227. }
  228. }
  229. // PointerType is a pointer to another type.
  230. type PointerType struct {
  231. Type Type
  232. }
  233. func (pt *PointerType) String(pm map[string]string, pkgOverride string) string {
  234. return "*" + pt.Type.String(pm, pkgOverride)
  235. }
  236. func (pt *PointerType) addImports(im map[string]bool) { pt.Type.addImports(im) }
  237. // PredeclaredType is a predeclared type such as "int".
  238. type PredeclaredType string
  239. func (pt PredeclaredType) String(pm map[string]string, pkgOverride string) string { return string(pt) }
  240. func (pt PredeclaredType) addImports(im map[string]bool) {}
  241. // The following code is intended to be called by the program generated by ../reflect.go.
  242. func InterfaceFromInterfaceType(it reflect.Type) (*Interface, error) {
  243. if it.Kind() != reflect.Interface {
  244. return nil, fmt.Errorf("%v is not an interface", it)
  245. }
  246. intf := &Interface{}
  247. for i := 0; i < it.NumMethod(); i++ {
  248. mt := it.Method(i)
  249. // TODO: need to skip unexported methods? or just raise an error?
  250. m := &Method{
  251. Name: mt.Name,
  252. }
  253. var err error
  254. m.In, m.Variadic, m.Out, err = funcArgsFromType(mt.Type)
  255. if err != nil {
  256. return nil, err
  257. }
  258. intf.Methods = append(intf.Methods, m)
  259. }
  260. return intf, nil
  261. }
  262. // t's Kind must be a reflect.Func.
  263. func funcArgsFromType(t reflect.Type) (in []*Parameter, variadic *Parameter, out []*Parameter, err error) {
  264. nin := t.NumIn()
  265. if t.IsVariadic() {
  266. nin--
  267. }
  268. var p *Parameter
  269. for i := 0; i < nin; i++ {
  270. p, err = parameterFromType(t.In(i))
  271. if err != nil {
  272. return
  273. }
  274. in = append(in, p)
  275. }
  276. if t.IsVariadic() {
  277. p, err = parameterFromType(t.In(nin).Elem())
  278. if err != nil {
  279. return
  280. }
  281. variadic = p
  282. }
  283. for i := 0; i < t.NumOut(); i++ {
  284. p, err = parameterFromType(t.Out(i))
  285. if err != nil {
  286. return
  287. }
  288. out = append(out, p)
  289. }
  290. return
  291. }
  292. func parameterFromType(t reflect.Type) (*Parameter, error) {
  293. tt, err := typeFromType(t)
  294. if err != nil {
  295. return nil, err
  296. }
  297. return &Parameter{Type: tt}, nil
  298. }
  299. var errorType = reflect.TypeOf((*error)(nil)).Elem()
  300. var byteType = reflect.TypeOf(byte(0))
  301. func typeFromType(t reflect.Type) (Type, error) {
  302. // Hack workaround for https://golang.org/issue/3853.
  303. // This explicit check should not be necessary.
  304. if t == byteType {
  305. return PredeclaredType("byte"), nil
  306. }
  307. if imp := t.PkgPath(); imp != "" {
  308. // PkgPath might return a path that includes "vendor"
  309. // These paths do not compile, so we need to remove everything
  310. // up to and including "/vendor/"
  311. // see https://github.com/golang/go/issues/12019
  312. if i := strings.LastIndex(imp, "/vendor/"); i != -1 {
  313. imp = imp[i+len("/vendor/"):]
  314. }
  315. return &NamedType{
  316. Package: imp,
  317. Type: t.Name(),
  318. }, nil
  319. }
  320. // only unnamed or predeclared types after here
  321. // Lots of types have element types. Let's do the parsing and error checking for all of them.
  322. var elemType Type
  323. switch t.Kind() {
  324. case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
  325. var err error
  326. elemType, err = typeFromType(t.Elem())
  327. if err != nil {
  328. return nil, err
  329. }
  330. }
  331. switch t.Kind() {
  332. case reflect.Array:
  333. return &ArrayType{
  334. Len: t.Len(),
  335. Type: elemType,
  336. }, nil
  337. case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  338. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
  339. reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String:
  340. return PredeclaredType(t.Kind().String()), nil
  341. case reflect.Chan:
  342. var dir ChanDir
  343. switch t.ChanDir() {
  344. case reflect.RecvDir:
  345. dir = RecvDir
  346. case reflect.SendDir:
  347. dir = SendDir
  348. }
  349. return &ChanType{
  350. Dir: dir,
  351. Type: elemType,
  352. }, nil
  353. case reflect.Func:
  354. in, variadic, out, err := funcArgsFromType(t)
  355. if err != nil {
  356. return nil, err
  357. }
  358. return &FuncType{
  359. In: in,
  360. Out: out,
  361. Variadic: variadic,
  362. }, nil
  363. case reflect.Interface:
  364. // Two special interfaces.
  365. if t.NumMethod() == 0 {
  366. return PredeclaredType("interface{}"), nil
  367. }
  368. if t == errorType {
  369. return PredeclaredType("error"), nil
  370. }
  371. case reflect.Map:
  372. kt, err := typeFromType(t.Key())
  373. if err != nil {
  374. return nil, err
  375. }
  376. return &MapType{
  377. Key: kt,
  378. Value: elemType,
  379. }, nil
  380. case reflect.Ptr:
  381. return &PointerType{
  382. Type: elemType,
  383. }, nil
  384. case reflect.Slice:
  385. return &ArrayType{
  386. Len: -1,
  387. Type: elemType,
  388. }, nil
  389. case reflect.Struct:
  390. if t.NumField() == 0 {
  391. return PredeclaredType("struct{}"), nil
  392. }
  393. }
  394. // TODO: Struct, UnsafePointer
  395. return nil, fmt.Errorf("can't yet turn %v (%v) into a model.Type", t, t.Kind())
  396. }