blob: b90b43c240a40d503906432cb4a61fc4504a5a60 [file] [log] [blame]
Damien Neil220c2022018-08-15 11:24:18 -07001// Copyright 2018 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
5// The protoc-gen-go binary is a protoc plugin to generate a Go protocol
6// buffer package.
7package main
8
9import (
Damien Neil7779e052018-09-07 14:14:06 -070010 "bytes"
11 "compress/gzip"
12 "crypto/sha256"
13 "encoding/hex"
Damien Neil3cf6e622018-09-11 13:53:14 -070014 "flag"
Damien Neil7779e052018-09-07 14:14:06 -070015 "fmt"
Damien Neilebc699d2018-09-13 08:50:13 -070016 "math"
Damien Neil7779e052018-09-07 14:14:06 -070017 "strconv"
Damien Neilcab8dfe2018-09-06 14:51:28 -070018 "strings"
Damien Neil7779e052018-09-07 14:14:06 -070019
20 "github.com/golang/protobuf/proto"
21 descpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
Damien Neil220c2022018-08-15 11:24:18 -070022 "google.golang.org/proto/protogen"
Damien Neil46abb572018-09-07 12:45:37 -070023 "google.golang.org/proto/reflect/protoreflect"
Damien Neil220c2022018-08-15 11:24:18 -070024)
25
Damien Neild4127922018-09-12 11:13:49 -070026// generatedCodeVersion indicates a version of the generated code.
27// It is incremented whenever an incompatibility between the generated code and
28// proto package is introduced; the generated code references
29// a constant, proto.ProtoPackageIsVersionN (where N is generatedCodeVersion).
30const generatedCodeVersion = 2
31
Damien Neil46abb572018-09-07 12:45:37 -070032const protoPackage = "github.com/golang/protobuf/proto"
33
Damien Neil220c2022018-08-15 11:24:18 -070034func main() {
Damien Neil3cf6e622018-09-11 13:53:14 -070035 var flags flag.FlagSet
36 // TODO: Decide what to do for backwards compatibility with plugins=grpc.
37 flags.String("plugins", "", "")
38 opts := &protogen.Options{
39 ParamFunc: flags.Set,
40 }
41 protogen.Run(opts, func(gen *protogen.Plugin) error {
Damien Neil220c2022018-08-15 11:24:18 -070042 for _, f := range gen.Files {
43 if !f.Generate {
44 continue
45 }
46 genFile(gen, f)
47 }
48 return nil
49 })
50}
51
Damien Neilcab8dfe2018-09-06 14:51:28 -070052type File struct {
53 *protogen.File
Damien Neil46abb572018-09-07 12:45:37 -070054 locationMap map[string][]*descpb.SourceCodeInfo_Location
55 descriptorVar string // var containing the gzipped FileDescriptorProto
56 init []string
Damien Neilcab8dfe2018-09-06 14:51:28 -070057}
58
59func genFile(gen *protogen.Plugin, file *protogen.File) {
60 f := &File{
61 File: file,
62 locationMap: make(map[string][]*descpb.SourceCodeInfo_Location),
63 }
64 for _, loc := range file.Proto.GetSourceCodeInfo().GetLocation() {
65 key := pathKey(loc.Path)
66 f.locationMap[key] = append(f.locationMap[key], loc)
67 }
68
Damien Neil46abb572018-09-07 12:45:37 -070069 // Determine the name of the var holding the file descriptor:
70 //
71 // fileDescriptor_<hash of filename>
72 filenameHash := sha256.Sum256([]byte(f.Desc.Path()))
73 f.descriptorVar = fmt.Sprintf("fileDescriptor_%s", hex.EncodeToString(filenameHash[:8]))
74
Damien Neil082ce922018-09-06 10:23:53 -070075 g := gen.NewGeneratedFile(f.GeneratedFilenamePrefix+".pb.go", f.GoImportPath)
Damien Neil220c2022018-08-15 11:24:18 -070076 g.P("// Code generated by protoc-gen-go. DO NOT EDIT.")
Damien Neilabc6fc12018-08-23 14:39:30 -070077 g.P("// source: ", f.Desc.Path())
Damien Neil220c2022018-08-15 11:24:18 -070078 g.P()
Damien Neilcab8dfe2018-09-06 14:51:28 -070079 const filePackageField = 2 // FileDescriptorProto.package
80 genComment(g, f, []int32{filePackageField})
81 g.P()
Damien Neil082ce922018-09-06 10:23:53 -070082 g.P("package ", f.GoPackageName)
Damien Neilc7d07d92018-08-22 13:46:02 -070083 g.P()
Damien Neild4127922018-09-12 11:13:49 -070084 g.P("// This is a compile-time assertion to ensure that this generated file")
85 g.P("// is compatible with the proto package it is being compiled against.")
86 g.P("// A compilation error at this line likely means your copy of the")
87 g.P("// proto package needs to be updated.")
88 g.P("const _ = ", protogen.GoIdent{
89 GoImportPath: protoPackage,
90 GoName: fmt.Sprintf("ProtoPackageIsVersion%d", generatedCodeVersion),
91 }, "// please upgrade the proto package")
92 g.P()
Damien Neilc7d07d92018-08-22 13:46:02 -070093
Damien Neil46abb572018-09-07 12:45:37 -070094 for _, enum := range f.Enums {
95 genEnum(gen, g, f, enum)
96 }
Damien Neilcab8dfe2018-09-06 14:51:28 -070097 for _, message := range f.Messages {
98 genMessage(gen, g, f, message)
Damien Neilc7d07d92018-08-22 13:46:02 -070099 }
Damien Neil220c2022018-08-15 11:24:18 -0700100
Damien Neil46abb572018-09-07 12:45:37 -0700101 if len(f.init) != 0 {
102 g.P("func init() {")
103 for _, s := range f.init {
104 g.P(s)
105 }
106 g.P("}")
107 g.P()
108 }
109
Damien Neil7779e052018-09-07 14:14:06 -0700110 genFileDescriptor(gen, g, f)
111}
112
Damien Neilcab8dfe2018-09-06 14:51:28 -0700113func genFileDescriptor(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File) {
Damien Neil7779e052018-09-07 14:14:06 -0700114 // Trim the source_code_info from the descriptor.
115 // Marshal and gzip it.
116 descProto := proto.Clone(f.Proto).(*descpb.FileDescriptorProto)
117 descProto.SourceCodeInfo = nil
118 b, err := proto.Marshal(descProto)
119 if err != nil {
120 gen.Error(err)
121 return
122 }
123 var buf bytes.Buffer
124 w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
125 w.Write(b)
126 w.Close()
127 b = buf.Bytes()
128
Damien Neil46abb572018-09-07 12:45:37 -0700129 g.P("func init() { proto.RegisterFile(", strconv.Quote(f.Desc.Path()), ", ", f.descriptorVar, ") }")
Damien Neil7779e052018-09-07 14:14:06 -0700130 g.P()
Damien Neil46abb572018-09-07 12:45:37 -0700131 g.P("var ", f.descriptorVar, " = []byte{")
Damien Neil7779e052018-09-07 14:14:06 -0700132 g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto")
133 for len(b) > 0 {
134 n := 16
135 if n > len(b) {
136 n = len(b)
137 }
138
139 s := ""
140 for _, c := range b[:n] {
141 s += fmt.Sprintf("0x%02x,", c)
142 }
143 g.P(s)
144
145 b = b[n:]
146 }
147 g.P("}")
148 g.P()
Damien Neil220c2022018-08-15 11:24:18 -0700149}
Damien Neilc7d07d92018-08-22 13:46:02 -0700150
Damien Neil46abb572018-09-07 12:45:37 -0700151func genEnum(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, enum *protogen.Enum) {
152 genComment(g, f, enum.Path)
153 // TODO: deprecation
154 g.P("type ", enum.GoIdent, " int32")
155 g.P("const (")
156 for _, value := range enum.Values {
157 genComment(g, f, value.Path)
158 // TODO: deprecation
159 g.P(value.GoIdent, " ", enum.GoIdent, " = ", value.Desc.Number())
160 }
161 g.P(")")
162 g.P()
163 nameMap := enum.GoIdent.GoName + "_name"
164 g.P("var ", nameMap, " = map[int32]string{")
165 generated := make(map[protoreflect.EnumNumber]bool)
166 for _, value := range enum.Values {
167 duplicate := ""
168 if _, present := generated[value.Desc.Number()]; present {
169 duplicate = "// Duplicate value: "
170 }
171 g.P(duplicate, value.Desc.Number(), ": ", strconv.Quote(string(value.Desc.Name())), ",")
172 generated[value.Desc.Number()] = true
173 }
174 g.P("}")
175 g.P()
176 valueMap := enum.GoIdent.GoName + "_value"
177 g.P("var ", valueMap, " = map[string]int32{")
178 for _, value := range enum.Values {
179 g.P(strconv.Quote(string(value.Desc.Name())), ": ", value.Desc.Number(), ",")
180 }
181 g.P("}")
182 g.P()
183 if enum.Desc.Syntax() != protoreflect.Proto3 {
184 g.P("func (x ", enum.GoIdent, ") Enum() *", enum.GoIdent, " {")
185 g.P("p := new(", enum.GoIdent, ")")
186 g.P("*p = x")
187 g.P("return p")
188 g.P("}")
189 g.P()
190 }
191 g.P("func (x ", enum.GoIdent, ") String() string {")
192 g.P("return ", protogen.GoIdent{GoImportPath: protoPackage, GoName: "EnumName"}, "(", enum.GoIdent, "_name, int32(x))")
193 g.P("}")
194 g.P()
195
196 if enum.Desc.Syntax() != protoreflect.Proto3 {
197 g.P("func (x *", enum.GoIdent, ") UnmarshalJSON(data []byte) error {")
198 g.P("value, err := ", protogen.GoIdent{GoImportPath: protoPackage, GoName: "UnmarshalJSONEnum"}, "(", enum.GoIdent, `_value, data, "`, enum.GoIdent, `")`)
199 g.P("if err != nil {")
200 g.P("return err")
201 g.P("}")
202 g.P("*x = ", enum.GoIdent, "(value)")
203 g.P("return nil")
204 g.P("}")
205 g.P()
206 }
207
208 var indexes []string
209 for i := 1; i < len(enum.Path); i += 2 {
210 indexes = append(indexes, strconv.Itoa(int(enum.Path[i])))
211 }
212 g.P("func (", enum.GoIdent, ") EnumDescriptor() ([]byte, []int) {")
213 g.P("return ", f.descriptorVar, ", []int{", strings.Join(indexes, ","), "}")
214 g.P("}")
215 g.P()
216
217 genWellKnownType(g, enum.GoIdent, enum.Desc)
218
Damien Neil46abb572018-09-07 12:45:37 -0700219 f.init = append(f.init, fmt.Sprintf("%s(%q, %s, %s)",
220 g.QualifiedGoIdent(protogen.GoIdent{
221 GoImportPath: protoPackage,
222 GoName: "RegisterEnum",
223 }),
Damien Neil658051b2018-09-10 12:26:21 -0700224 enumRegistryName(enum), nameMap, valueMap,
Damien Neil46abb572018-09-07 12:45:37 -0700225 ))
226}
227
Damien Neil658051b2018-09-10 12:26:21 -0700228// enumRegistryName returns the name used to register an enum with the proto
229// package registry.
230//
231// Confusingly, this is <proto_package>.<go_ident>. This probably should have
232// been the full name of the proto enum type instead, but changing it at this
233// point would require thought.
234func enumRegistryName(enum *protogen.Enum) string {
235 // Find the FileDescriptor for this enum.
236 var desc protoreflect.Descriptor = enum.Desc
237 for {
238 p, ok := desc.Parent()
239 if !ok {
240 break
241 }
242 desc = p
243 }
244 fdesc := desc.(protoreflect.FileDescriptor)
245 return string(fdesc.Package()) + "." + enum.GoIdent.GoName
246}
247
Damien Neilcab8dfe2018-09-06 14:51:28 -0700248func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, message *protogen.Message) {
Damien Neil658051b2018-09-10 12:26:21 -0700249 for _, e := range message.Enums {
250 genEnum(gen, g, f, e)
Damien Neil46abb572018-09-07 12:45:37 -0700251 }
252
Damien Neilcab8dfe2018-09-06 14:51:28 -0700253 genComment(g, f, message.Path)
Damien Neil658051b2018-09-10 12:26:21 -0700254 // TODO: deprecation
Damien Neilcab8dfe2018-09-06 14:51:28 -0700255 g.P("type ", message.GoIdent, " struct {")
Damien Neil658051b2018-09-10 12:26:21 -0700256 for _, field := range message.Fields {
257 if field.Desc.OneofType() != nil {
258 // TODO oneofs
259 continue
260 }
261 genComment(g, f, field.Path)
262 g.P(field.GoIdent, " ", fieldGoType(g, field), fmt.Sprintf(" `protobuf:%q json:%q`", fieldProtobufTag(field), fieldJSONTag(field)))
263 }
264 g.P("XXX_NoUnkeyedLiteral struct{} `json:\"-\"`")
265 // TODO XXX_InternalExtensions
266 g.P("XXX_unrecognized []byte `json:\"-\"`")
267 g.P("XXX_sizecache int32 `json:\"-\"`")
Damien Neilc7d07d92018-08-22 13:46:02 -0700268 g.P("}")
269 g.P()
270
Damien Neila1c6abc2018-09-12 13:36:34 -0700271 // Reset
272 g.P("func (m *", message.GoIdent, ") Reset() { *m = ", message.GoIdent, "{} }")
273 // String
274 g.P("func (m *", message.GoIdent, ") String() string { return ", protogen.GoIdent{
275 GoImportPath: protoPackage,
276 GoName: "CompactTextString",
277 }, "(m) }")
278 // ProtoMessage
279 g.P("func (*", message.GoIdent, ") ProtoMessage() {}")
280 // Descriptor
281 var indexes []string
282 for i := 1; i < len(message.Path); i += 2 {
283 indexes = append(indexes, strconv.Itoa(int(message.Path[i])))
284 }
285 g.P("func (*", message.GoIdent, ") Descriptor() ([]byte, []int) {")
286 g.P("return ", f.descriptorVar, ", []int{", strings.Join(indexes, ","), "}")
287 g.P("}")
288 // TODO: extension support methods
289
290 // Table-driven proto support.
291 //
292 // TODO: It does not scale to keep adding another method for every
293 // operation on protos that we want to switch over to using the
294 // table-driven approach. Instead, we should only add a single method
295 // that allows getting access to the *InternalMessageInfo struct and then
296 // calling Unmarshal, Marshal, Merge, Size, and Discard directly on that.
297 messageInfoVar := "xxx_messageInfo_" + message.GoIdent.GoName
298 // XXX_Unmarshal
299 g.P("func (m *", message.GoIdent, ") XXX_Unmarshal(b []byte) error {")
300 g.P("return ", messageInfoVar, ".Unmarshal(m, b)")
301 g.P("}")
302 // XXX_Marshal
303 g.P("func (m *", message.GoIdent, ") XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {")
304 g.P("return ", messageInfoVar, ".Marshal(b, m, deterministic)")
305 g.P("}")
306 // XXX_Merge
307 g.P("func (m *", message.GoIdent, ") XXX_Merge(src proto.Message) {")
308 g.P(messageInfoVar, ".Merge(m, src)")
309 g.P("}")
310 // XXX_Size
311 g.P("func (m *", message.GoIdent, ") XXX_Size() int {")
312 g.P("return ", messageInfoVar, ".Size(m)")
313 g.P("}")
314 // XXX_DiscardUnknown
315 g.P("func (m *", message.GoIdent, ") XXX_DiscardUnknown() {")
316 g.P(messageInfoVar, ".DiscardUnknown(m)")
317 g.P("}")
318 g.P()
319 g.P("var ", messageInfoVar, " ", protogen.GoIdent{
320 GoImportPath: protoPackage,
321 GoName: "InternalMessageInfo",
322 })
323 g.P()
324
Damien Neilebc699d2018-09-13 08:50:13 -0700325 // Constants and vars holding the default values of fields.
326 for _, field := range message.Fields {
327 if !field.Desc.HasDefault() {
328 continue
329 }
330 defVarName := "Default_" + message.GoIdent.GoName + "_" + field.GoIdent.GoName
331 def := field.Desc.Default()
332 switch field.Desc.Kind() {
333 case protoreflect.StringKind:
334 g.P("const ", defVarName, " string = ", strconv.Quote(def.String()))
335 case protoreflect.BytesKind:
336 g.P("var ", defVarName, " []byte = []byte(", strconv.Quote(string(def.Bytes())), ")")
337 case protoreflect.EnumKind:
338 enum := field.EnumType
339 evalue := enum.Values[enum.Desc.Values().ByNumber(def.Enum()).Index()]
340 g.P("const ", defVarName, " ", field.EnumType.GoIdent, " = ", evalue.GoIdent)
341 case protoreflect.FloatKind, protoreflect.DoubleKind:
342 // Floating point numbers need extra handling for -Inf/Inf/NaN.
343 f := field.Desc.Default().Float()
344 goType := "float64"
345 if field.Desc.Kind() == protoreflect.FloatKind {
346 goType = "float32"
347 }
348 // funcCall returns a call to a function in the math package,
349 // possibly converting the result to float32.
350 funcCall := func(fn, param string) string {
351 s := g.QualifiedGoIdent(protogen.GoIdent{
352 GoImportPath: "math",
353 GoName: fn,
354 }) + param
355 if goType != "float64" {
356 s = goType + "(" + s + ")"
357 }
358 return s
359 }
360 switch {
361 case math.IsInf(f, -1):
362 g.P("var ", defVarName, " ", goType, " = ", funcCall("Inf", "(-1)"))
363 case math.IsInf(f, 1):
364 g.P("var ", defVarName, " ", goType, " = ", funcCall("Inf", "(1)"))
365 case math.IsNaN(f):
366 g.P("var ", defVarName, " ", goType, " = ", funcCall("NaN", "()"))
367 default:
368 g.P("const ", defVarName, " ", goType, " = ", f)
369 }
370 default:
371 goType := fieldGoType(g, field)
372 goType = strings.TrimPrefix(goType, "*")
373 g.P("const ", defVarName, " ", goType, " = ", def.Interface())
374 }
375 }
376 g.P()
377
Damien Neila1c6abc2018-09-12 13:36:34 -0700378 // TODO: getters
379
Damien Neilcab8dfe2018-09-06 14:51:28 -0700380 for _, nested := range message.Messages {
381 genMessage(gen, g, f, nested)
Damien Neilc7d07d92018-08-22 13:46:02 -0700382 }
383}
Damien Neilcab8dfe2018-09-06 14:51:28 -0700384
Damien Neil658051b2018-09-10 12:26:21 -0700385func fieldGoType(g *protogen.GeneratedFile, field *protogen.Field) string {
386 // TODO: map types
387 var typ string
388 switch field.Desc.Kind() {
389 case protoreflect.BoolKind:
390 typ = "bool"
391 case protoreflect.EnumKind:
392 typ = g.QualifiedGoIdent(field.EnumType.GoIdent)
393 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
394 typ = "int32"
395 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
396 typ = "uint32"
397 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
398 typ = "int64"
399 case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
400 typ = "uint64"
401 case protoreflect.FloatKind:
402 typ = "float32"
403 case protoreflect.DoubleKind:
404 typ = "float64"
405 case protoreflect.StringKind:
406 typ = "string"
407 case protoreflect.BytesKind:
408 typ = "[]byte"
409 case protoreflect.MessageKind, protoreflect.GroupKind:
410 typ = "*" + g.QualifiedGoIdent(field.MessageType.GoIdent)
411 }
412 if field.Desc.Cardinality() == protoreflect.Repeated {
413 return "[]" + typ
414 }
415 if field.Desc.Syntax() == protoreflect.Proto3 {
416 return typ
417 }
418 if field.Desc.OneofType() != nil {
419 return typ
420 }
421 nonPointerKinds := map[protoreflect.Kind]bool{
422 protoreflect.GroupKind: true,
423 protoreflect.MessageKind: true,
424 protoreflect.BytesKind: true,
425 }
426 if !nonPointerKinds[field.Desc.Kind()] {
427 return "*" + typ
428 }
429 return typ
430}
431
432func fieldProtobufTag(field *protogen.Field) string {
433 var tag []string
434 // wire type
435 tag = append(tag, wireTypes[field.Desc.Kind()])
436 // field number
437 tag = append(tag, strconv.Itoa(int(field.Desc.Number())))
438 // cardinality
439 switch field.Desc.Cardinality() {
440 case protoreflect.Optional:
441 tag = append(tag, "opt")
442 case protoreflect.Required:
443 tag = append(tag, "req")
444 case protoreflect.Repeated:
445 tag = append(tag, "rep")
446 }
Damien Neil658051b2018-09-10 12:26:21 -0700447 // TODO: packed
448 // name
449 name := string(field.Desc.Name())
450 if field.Desc.Kind() == protoreflect.GroupKind {
451 // The name of the FieldDescriptor for a group field is
452 // lowercased. To find the original capitalization, we
453 // look in the field's MessageType.
454 name = string(field.MessageType.Desc.Name())
455 }
456 tag = append(tag, "name="+name)
457 // JSON name
458 if jsonName := field.Desc.JSONName(); jsonName != "" && jsonName != name {
459 tag = append(tag, "json="+jsonName)
460 }
461 // proto3
462 if field.Desc.Syntax() == protoreflect.Proto3 {
463 tag = append(tag, "proto3")
464 }
465 // enum
466 if field.Desc.Kind() == protoreflect.EnumKind {
467 tag = append(tag, "enum="+enumRegistryName(field.EnumType))
468 }
469 // oneof
470 if field.Desc.OneofType() != nil {
471 tag = append(tag, "oneof")
472 }
Damien Neilebc699d2018-09-13 08:50:13 -0700473 // default value
474 // This must appear last in the tag, since commas in strings aren't escaped.
475 if field.Desc.HasDefault() {
476 var def string
477 switch field.Desc.Kind() {
478 case protoreflect.BoolKind:
479 if field.Desc.Default().Bool() {
480 def = "1"
481 } else {
482 def = "0"
483 }
484 case protoreflect.BytesKind:
485 def = string(field.Desc.Default().Bytes())
486 case protoreflect.FloatKind, protoreflect.DoubleKind:
487 f := field.Desc.Default().Float()
488 switch {
489 case math.IsInf(f, -1):
490 def = "-inf"
491 case math.IsInf(f, 1):
492 def = "inf"
493 case math.IsNaN(f):
494 def = "nan"
495 default:
496 def = fmt.Sprint(f)
497 }
498 default:
499 def = fmt.Sprint(field.Desc.Default().Interface())
500 }
501 tag = append(tag, "def="+def)
502 }
Damien Neil658051b2018-09-10 12:26:21 -0700503 return strings.Join(tag, ",")
504}
505
506var wireTypes = map[protoreflect.Kind]string{
507 protoreflect.BoolKind: "varint",
508 protoreflect.EnumKind: "varint",
509 protoreflect.Int32Kind: "varint",
510 protoreflect.Sint32Kind: "zigzag32",
511 protoreflect.Uint32Kind: "varint",
512 protoreflect.Int64Kind: "varint",
513 protoreflect.Sint64Kind: "zigzag64",
514 protoreflect.Uint64Kind: "varint",
515 protoreflect.Sfixed32Kind: "fixed32",
516 protoreflect.Fixed32Kind: "fixed32",
517 protoreflect.FloatKind: "fixed32",
518 protoreflect.Sfixed64Kind: "fixed64",
519 protoreflect.Fixed64Kind: "fixed64",
520 protoreflect.DoubleKind: "fixed64",
521 protoreflect.StringKind: "bytes",
522 protoreflect.BytesKind: "bytes",
523 protoreflect.MessageKind: "bytes",
524 protoreflect.GroupKind: "group",
525}
526
527func fieldJSONTag(field *protogen.Field) string {
528 return string(field.Desc.Name()) + ",omitempty"
529}
530
Damien Neilcab8dfe2018-09-06 14:51:28 -0700531func genComment(g *protogen.GeneratedFile, f *File, path []int32) {
532 for _, loc := range f.locationMap[pathKey(path)] {
533 if loc.LeadingComments == nil {
534 continue
535 }
536 for _, line := range strings.Split(strings.TrimSuffix(loc.GetLeadingComments(), "\n"), "\n") {
537 g.P("//", line)
538 }
539 return
540 }
541}
542
543// pathKey converts a location path to a string suitable for use as a map key.
544func pathKey(path []int32) string {
545 var buf []byte
546 for i, x := range path {
547 if i != 0 {
548 buf = append(buf, ',')
549 }
550 buf = strconv.AppendInt(buf, int64(x), 10)
551 }
552 return string(buf)
553}
Damien Neil46abb572018-09-07 12:45:37 -0700554
555func genWellKnownType(g *protogen.GeneratedFile, ident protogen.GoIdent, desc protoreflect.Descriptor) {
556 if wellKnownTypes[desc.FullName()] {
557 g.P("func (", ident, `) XXX_WellKnownType() string { return "`, desc.Name(), `" }`)
558 g.P()
559 }
560}
561
562// Names of messages and enums for which we will generate XXX_WellKnownType methods.
563var wellKnownTypes = map[protoreflect.FullName]bool{
564 "google.protobuf.NullValue": true,
565}