wrappers.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. // Copyright 2018 Twitch Interactive, Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"). You may not
  4. // use this file except in compliance with the License. A copy of the License is
  5. // located at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // or in the "license" file accompanying this file. This file is distributed on
  10. // an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  11. // express or implied. See the License for the specific language governing
  12. // permissions and limitations under the License.
  13. //
  14. //
  15. // This file contains some code from https://github.com/golang/protobuf:
  16. // Copyright 2010 The Go Authors. All rights reserved.
  17. // https://github.com/golang/protobuf
  18. //
  19. // Redistribution and use in source and binary forms, with or without
  20. // modification, are permitted provided that the following conditions are
  21. // met:
  22. //
  23. // * Redistributions of source code must retain the above copyright
  24. // notice, this list of conditions and the following disclaimer.
  25. // * Redistributions in binary form must reproduce the above
  26. // copyright notice, this list of conditions and the following disclaimer
  27. // in the documentation and/or other materials provided with the
  28. // distribution.
  29. // * Neither the name of Google Inc. nor the names of its
  30. // contributors may be used to endorse or promote products derived from
  31. // this software without specific prior written permission.
  32. //
  33. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  34. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  35. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  36. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  37. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  38. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  39. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  40. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  41. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  42. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  43. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. package gen
  45. import (
  46. "fmt"
  47. "path"
  48. "strconv"
  49. "strings"
  50. "go-common/app/tool/liverpc/protoc-gen-liverpc/gen/stringutils"
  51. "github.com/golang/protobuf/protoc-gen-go/descriptor"
  52. plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
  53. )
  54. // Each type we import as a protocol buffer (other than FileDescriptorProto) needs
  55. // a pointer to the FileDescriptorProto that represents it. These types achieve that
  56. // wrapping by placing each Proto inside a struct with the pointer to its File. The
  57. // structs have the same names as their contents, with "Proto" removed.
  58. // FileDescriptor is used to store the things that it points to.
  59. // WrapTypes walks the incoming data, wrapping DescriptorProtos, EnumDescriptorProtos
  60. // and FileDescriptorProtos into file-referenced objects within the Generator.
  61. // It also creates the list of files to generate and so should be called before GenerateAllFiles.
  62. func WrapTypes(req *plugin.CodeGeneratorRequest) (genFiles, allFiles []*FileDescriptor, allFilesByName map[string]*FileDescriptor) {
  63. allFiles = make([]*FileDescriptor, 0, len(req.ProtoFile))
  64. allFilesByName = make(map[string]*FileDescriptor, len(allFiles))
  65. for _, f := range req.ProtoFile {
  66. // We must wrap the descriptors before we wrap the enums
  67. descs := wrapDescriptors(f)
  68. buildNestedDescriptors(descs)
  69. enums := wrapEnumDescriptors(f, descs)
  70. buildNestedEnums(descs, enums)
  71. exts := wrapExtensions(f)
  72. svcs := wrapServices(f)
  73. fd := &FileDescriptor{
  74. FileDescriptorProto: f,
  75. Services: svcs,
  76. Descriptors: descs,
  77. Enums: enums,
  78. Extensions: exts,
  79. proto3: fileIsProto3(f),
  80. }
  81. extractComments(fd)
  82. allFiles = append(allFiles, fd)
  83. allFilesByName[f.GetName()] = fd
  84. }
  85. for _, fd := range allFiles {
  86. fd.Imported = wrapImported(fd.FileDescriptorProto, allFilesByName)
  87. }
  88. genFiles = make([]*FileDescriptor, 0, len(req.FileToGenerate))
  89. for _, fileName := range req.FileToGenerate {
  90. fd := allFilesByName[fileName]
  91. if fd == nil {
  92. Fail("could not find file named", fileName)
  93. }
  94. fd.Index = len(genFiles)
  95. genFiles = append(genFiles, fd)
  96. }
  97. return genFiles, allFiles, allFilesByName
  98. }
  99. // The file and package name method are common to messages and enums.
  100. type common struct {
  101. file *descriptor.FileDescriptorProto // File this object comes from.
  102. }
  103. func (c *common) File() *descriptor.FileDescriptorProto { return c.file }
  104. func fileIsProto3(file *descriptor.FileDescriptorProto) bool {
  105. return file.GetSyntax() == "proto3"
  106. }
  107. // Descriptor represents a protocol buffer message.
  108. type Descriptor struct {
  109. common
  110. *descriptor.DescriptorProto
  111. Parent *Descriptor // The containing message, if any.
  112. nested []*Descriptor // Inner messages, if any.
  113. enums []*EnumDescriptor // Inner enums, if any.
  114. ext []*ExtensionDescriptor // Extensions, if any.
  115. typename []string // Cached typename vector.
  116. index int // The index into the container, whether the file or another message.
  117. path string // The SourceCodeInfo path as comma-separated integers.
  118. group bool
  119. }
  120. func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto, index int) *Descriptor {
  121. d := &Descriptor{
  122. common: common{file},
  123. DescriptorProto: desc,
  124. Parent: parent,
  125. index: index,
  126. }
  127. if parent == nil {
  128. d.path = fmt.Sprintf("%d,%d", messagePath, index)
  129. } else {
  130. d.path = fmt.Sprintf("%s,%d,%d", parent.path, messageMessagePath, index)
  131. }
  132. // The only way to distinguish a group from a message is whether
  133. // the containing message has a TYPE_GROUP field that matches.
  134. if parent != nil {
  135. parts := d.TypeName()
  136. if file.Package != nil {
  137. parts = append([]string{*file.Package}, parts...)
  138. }
  139. exp := "." + strings.Join(parts, ".")
  140. for _, field := range parent.Field {
  141. if field.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP && field.GetTypeName() == exp {
  142. d.group = true
  143. break
  144. }
  145. }
  146. }
  147. for _, field := range desc.Extension {
  148. d.ext = append(d.ext, &ExtensionDescriptor{common{file}, field, d})
  149. }
  150. return d
  151. }
  152. // Return a slice of all the Descriptors defined within this file
  153. func wrapDescriptors(file *descriptor.FileDescriptorProto) []*Descriptor {
  154. sl := make([]*Descriptor, 0, len(file.MessageType)+10)
  155. for i, desc := range file.MessageType {
  156. sl = wrapThisDescriptor(sl, desc, nil, file, i)
  157. }
  158. return sl
  159. }
  160. // Wrap this Descriptor, recursively
  161. func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto, index int) []*Descriptor {
  162. sl = append(sl, newDescriptor(desc, parent, file, index))
  163. me := sl[len(sl)-1]
  164. for i, nested := range desc.NestedType {
  165. sl = wrapThisDescriptor(sl, nested, me, file, i)
  166. }
  167. return sl
  168. }
  169. func buildNestedDescriptors(descs []*Descriptor) {
  170. for _, desc := range descs {
  171. if len(desc.NestedType) != 0 {
  172. for _, nest := range descs {
  173. if nest.Parent == desc {
  174. desc.nested = append(desc.nested, nest)
  175. }
  176. }
  177. if len(desc.nested) != len(desc.NestedType) {
  178. Fail("internal error: nesting failure for", desc.GetName())
  179. }
  180. }
  181. }
  182. }
  183. // TypeName returns the elements of the dotted type name.
  184. // The package name is not part of this name.
  185. func (d *Descriptor) TypeName() []string {
  186. if d.typename != nil {
  187. return d.typename
  188. }
  189. n := 0
  190. for parent := d; parent != nil; parent = parent.Parent {
  191. n++
  192. }
  193. s := make([]string, n)
  194. for parent := d; parent != nil; parent = parent.Parent {
  195. n--
  196. s[n] = parent.GetName()
  197. }
  198. d.typename = s
  199. return s
  200. }
  201. // EnumDescriptor describes an enum. If it's at top level, its parent will be nil.
  202. // Otherwise it will be the descriptor of the message in which it is defined.
  203. type EnumDescriptor struct {
  204. common
  205. *descriptor.EnumDescriptorProto
  206. parent *Descriptor // The containing message, if any.
  207. typename []string // Cached typename vector.
  208. index int // The index into the container, whether the file or a message.
  209. path string // The SourceCodeInfo path as comma-separated integers.
  210. }
  211. // Construct a new EnumDescriptor
  212. func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto, index int) *EnumDescriptor {
  213. ed := &EnumDescriptor{
  214. common: common{file},
  215. EnumDescriptorProto: desc,
  216. parent: parent,
  217. index: index,
  218. }
  219. if parent == nil {
  220. ed.path = fmt.Sprintf("%d,%d", enumPath, index)
  221. } else {
  222. ed.path = fmt.Sprintf("%s,%d,%d", parent.path, messageEnumPath, index)
  223. }
  224. return ed
  225. }
  226. // Return a slice of all the EnumDescriptors defined within this file
  227. func wrapEnumDescriptors(file *descriptor.FileDescriptorProto, descs []*Descriptor) []*EnumDescriptor {
  228. sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
  229. // Top-level enums.
  230. for i, enum := range file.EnumType {
  231. sl = append(sl, newEnumDescriptor(enum, nil, file, i))
  232. }
  233. // Enums within messages. Enums within embedded messages appear in the outer-most message.
  234. for _, nested := range descs {
  235. for i, enum := range nested.EnumType {
  236. sl = append(sl, newEnumDescriptor(enum, nested, file, i))
  237. }
  238. }
  239. return sl
  240. }
  241. func buildNestedEnums(descs []*Descriptor, enums []*EnumDescriptor) {
  242. for _, desc := range descs {
  243. if len(desc.EnumType) != 0 {
  244. for _, enum := range enums {
  245. if enum.parent == desc {
  246. desc.enums = append(desc.enums, enum)
  247. }
  248. }
  249. if len(desc.enums) != len(desc.EnumType) {
  250. Fail("internal error: enum nesting failure for", desc.GetName())
  251. }
  252. }
  253. }
  254. }
  255. // TypeName returns the elements of the dotted type name.
  256. // The package name is not part of this name.
  257. func (e *EnumDescriptor) TypeName() (s []string) {
  258. if e.typename != nil {
  259. return e.typename
  260. }
  261. name := e.GetName()
  262. if e.parent == nil {
  263. s = make([]string, 1)
  264. } else {
  265. pname := e.parent.TypeName()
  266. s = make([]string, len(pname)+1)
  267. copy(s, pname)
  268. }
  269. s[len(s)-1] = name
  270. e.typename = s
  271. return s
  272. }
  273. // ExtensionDescriptor describes an extension. If it's at top level, its parent will be nil.
  274. // Otherwise it will be the descriptor of the message in which it is defined.
  275. type ExtensionDescriptor struct {
  276. common
  277. *descriptor.FieldDescriptorProto
  278. parent *Descriptor // The containing message, if any.
  279. }
  280. // Return a slice of all the top-level ExtensionDescriptors defined within this file.
  281. func wrapExtensions(file *descriptor.FileDescriptorProto) []*ExtensionDescriptor {
  282. var sl []*ExtensionDescriptor
  283. for _, field := range file.Extension {
  284. sl = append(sl, &ExtensionDescriptor{common{file}, field, nil})
  285. }
  286. return sl
  287. }
  288. // TypeName returns the elements of the dotted type name.
  289. // The package name is not part of this name.
  290. func (e *ExtensionDescriptor) TypeName() (s []string) {
  291. name := e.GetName()
  292. if e.parent == nil {
  293. // top-level extension
  294. s = make([]string, 1)
  295. } else {
  296. pname := e.parent.TypeName()
  297. s = make([]string, len(pname)+1)
  298. copy(s, pname)
  299. }
  300. s[len(s)-1] = name
  301. return s
  302. }
  303. // DescName returns the variable name used for the generated descriptor.
  304. func (e *ExtensionDescriptor) DescName() string {
  305. // The full type name.
  306. typeName := e.TypeName()
  307. // Each scope of the extension is individually CamelCased, and all are joined with "_" with an "E_" prefix.
  308. for i, s := range typeName {
  309. typeName[i] = stringutils.CamelCase(s)
  310. }
  311. return "E_" + strings.Join(typeName, "_")
  312. }
  313. // ImportedDescriptor describes a type that has been publicly imported from another file.
  314. type ImportedDescriptor struct {
  315. common
  316. Object Object
  317. }
  318. // Return a slice of all the types that are publicly imported into this file.
  319. func wrapImported(file *descriptor.FileDescriptorProto, fileMap map[string]*FileDescriptor) (sl []*ImportedDescriptor) {
  320. for _, index := range file.PublicDependency {
  321. df := fileMap[file.Dependency[index]]
  322. for _, d := range df.Descriptors {
  323. if d.GetOptions().GetMapEntry() {
  324. continue
  325. }
  326. sl = append(sl, &ImportedDescriptor{common{file}, d})
  327. }
  328. for _, e := range df.Enums {
  329. sl = append(sl, &ImportedDescriptor{common{file}, e})
  330. }
  331. for _, ext := range df.Extensions {
  332. sl = append(sl, &ImportedDescriptor{common{file}, ext})
  333. }
  334. }
  335. return
  336. }
  337. // TypeName ...
  338. func (id *ImportedDescriptor) TypeName() []string { return id.Object.TypeName() }
  339. // ServiceDescriptor represents a protocol buffer service.
  340. type ServiceDescriptor struct {
  341. common
  342. *descriptor.ServiceDescriptorProto
  343. Methods []*MethodDescriptor
  344. Index int // index of the ServiceDescriptorProto in its parent FileDescriptorProto
  345. Path string // The SourceCodeInfo path as comma-separated integers.
  346. }
  347. // TypeName ...
  348. func (sd *ServiceDescriptor) TypeName() []string {
  349. return []string{sd.GetName()}
  350. }
  351. func wrapServices(file *descriptor.FileDescriptorProto) (sl []*ServiceDescriptor) {
  352. for i, svc := range file.Service {
  353. sd := &ServiceDescriptor{
  354. common: common{file},
  355. ServiceDescriptorProto: svc,
  356. Index: i,
  357. Path: fmt.Sprintf("%d,%d", servicePath, i),
  358. }
  359. for j, method := range svc.Method {
  360. md := &MethodDescriptor{
  361. common: common{file},
  362. MethodDescriptorProto: method,
  363. service: sd,
  364. Path: fmt.Sprintf("%d,%d,%d,%d", servicePath, i, serviceMethodPath, j),
  365. }
  366. sd.Methods = append(sd.Methods, md)
  367. }
  368. sl = append(sl, sd)
  369. }
  370. return sl
  371. }
  372. // MethodDescriptor represents an RPC method on a protocol buffer
  373. // service.
  374. type MethodDescriptor struct {
  375. common
  376. *descriptor.MethodDescriptorProto
  377. service *ServiceDescriptor
  378. Path string // The SourceCodeInfo path as comma-separated integers.
  379. }
  380. // TypeName ...
  381. func (md *MethodDescriptor) TypeName() []string {
  382. return []string{md.service.GetName(), md.GetName()}
  383. }
  384. // FileDescriptor describes an protocol buffer descriptor file (.proto).
  385. // It includes slices of all the messages and enums defined within it.
  386. // Those slices are constructed by WrapTypes.
  387. type FileDescriptor struct {
  388. *descriptor.FileDescriptorProto
  389. Descriptors []*Descriptor // All the messages defined in this file.
  390. Enums []*EnumDescriptor // All the enums defined in this file.
  391. Extensions []*ExtensionDescriptor // All the top-level extensions defined in this file.
  392. Imported []*ImportedDescriptor // All types defined in files publicly imported by this file.
  393. Services []*ServiceDescriptor // All the services defined in this file.
  394. // Comments, stored as a map of path (comma-separated integers) to the comment.
  395. Comments map[string]*descriptor.SourceCodeInfo_Location
  396. Index int // The index of this file in the list of files to generate code for
  397. proto3 bool // whether to generate proto3 code for this file
  398. }
  399. // VarName is the variable name used in generated code to refer to the
  400. // compressed bytes of this descriptor. It is not exported, so it is only valid
  401. // inside the generated package.
  402. //
  403. // protoc-gen-go writes its own version of this file, but so does
  404. // protoc-gen-gogo - with a different name! Twirp aims to be compatible with
  405. // both; the simplest way forward is to write the file descriptor again as
  406. // another variable that we control.
  407. func (d *FileDescriptor) VarName() string { return fmt.Sprintf("twirpFileDescriptor%d", d.Index) }
  408. // PackageComments get pkg comments
  409. func (d *FileDescriptor) PackageComments() string {
  410. if loc, ok := d.Comments[strconv.Itoa(packagePath)]; ok {
  411. text := strings.TrimSuffix(loc.GetLeadingComments(), "\n")
  412. return text
  413. }
  414. return ""
  415. }
  416. // BaseFileName name strip extension
  417. func (d *FileDescriptor) BaseFileName() string {
  418. name := *d.Name
  419. if ext := path.Ext(name); ext == ".proto" || ext == ".protodevel" {
  420. name = name[:len(name)-len(ext)]
  421. }
  422. return name
  423. }
  424. func extractComments(file *FileDescriptor) {
  425. file.Comments = make(map[string]*descriptor.SourceCodeInfo_Location)
  426. for _, loc := range file.GetSourceCodeInfo().GetLocation() {
  427. if loc.LeadingComments == nil {
  428. continue
  429. }
  430. var p []string
  431. for _, n := range loc.Path {
  432. p = append(p, strconv.Itoa(int(n)))
  433. }
  434. file.Comments[strings.Join(p, ",")] = loc
  435. }
  436. }
  437. // Object is an interface abstracting the abilities shared by enums, messages, extensions and imported objects.
  438. type Object interface {
  439. TypeName() []string
  440. File() *descriptor.FileDescriptorProto
  441. }
  442. // The SourceCodeInfo message describes the location of elements of a parsed
  443. // .proto file by way of a "path", which is a sequence of integers that
  444. // describe the route from a FileDescriptorProto to the relevant submessage.
  445. // The path alternates between a field number of a repeated field, and an index
  446. // into that repeated field. The constants below define the field numbers that
  447. // are used.
  448. //
  449. // See descriptor.proto for more information about this.
  450. const (
  451. // tag numbers in FileDescriptorProto
  452. packagePath = 2 // package
  453. messagePath = 4 // message_type
  454. enumPath = 5 // enum_type
  455. servicePath = 6 // service
  456. // tag numbers in DescriptorProto
  457. //messageFieldPath = 2 // field
  458. messageMessagePath = 3 // nested_type
  459. messageEnumPath = 4 // enum_type
  460. //messageOneofPath = 8 // oneof_decl
  461. // tag numbers in ServiceDescriptorProto
  462. //serviceNamePath = 1 // name
  463. serviceMethodPath = 2 // method
  464. //serviceOptionsPath = 3 // options
  465. // tag numbers in MethodDescriptorProto
  466. //methodNamePath = 1 // name
  467. //methodInputPath = 2 // input_type
  468. //methodOutputPath = 3 // output_type
  469. )