blob: b75aa083ee923da0cc14ad9f5bf2590c2a975e42 [file] [log] [blame]
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001// Go support for Protocol Buffers - Google's data interchange format
2//
David Symondsee6e9c52012-11-29 08:51:07 +11003// Copyright 2010 The Go Authors. All rights reserved.
Rob Pikeaf82b4e2010-04-30 15:19:25 -07004// http://code.google.com/p/goprotobuf/
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32/*
33 The code generator for the plugin for the Google protocol buffer compiler.
34 It generates Go code from the protocol buffer description files read by the
35 main routine.
Rob Pikeaf82b4e2010-04-30 15:19:25 -070036*/
37package generator
38
39import (
40 "bytes"
41 "fmt"
David Symondsb1d55a02011-04-08 09:55:06 +100042 "go/parser"
43 "go/printer"
44 "go/token"
Rob Pikeaf82b4e2010-04-30 15:19:25 -070045 "log"
46 "os"
Rob Pike87af39e2010-07-19 10:48:02 -070047 "path"
David Symonds79eae332010-10-16 11:33:20 +110048 "strconv"
Rob Pikeaf82b4e2010-04-30 15:19:25 -070049 "strings"
David Symonds162d0032012-06-28 09:44:46 -070050 "unicode"
51 "unicode/utf8"
Rob Pikeaf82b4e2010-04-30 15:19:25 -070052
Rob Pike3f6f2d82011-12-18 13:55:35 -080053 "code.google.com/p/goprotobuf/proto"
Rob Pikeb7907bf2012-02-13 14:25:20 +110054 descriptor "code.google.com/p/goprotobuf/protoc-gen-go/descriptor"
55 plugin "code.google.com/p/goprotobuf/protoc-gen-go/plugin"
Rob Pikeaf82b4e2010-04-30 15:19:25 -070056)
57
58// A Plugin provides functionality to add to the output during Go code generation,
59// such as to produce RPC stubs.
60type Plugin interface {
61 // Name identifies the plugin.
Rob Pikec9e7d972010-06-10 10:30:22 -070062 Name() string
63 // Init is called once after data structures are built but before
64 // code generation begins.
65 Init(g *Generator)
66 // Generate produces the code generated by the plugin for this file,
67 // except for the imports, by calling the generator's methods P, In, and Out.
68 Generate(file *FileDescriptor)
Rob Pikeaf82b4e2010-04-30 15:19:25 -070069 // GenerateImports produces the import declarations for this file.
Rob Pikec9e7d972010-06-10 10:30:22 -070070 // It is called after Generate.
71 GenerateImports(file *FileDescriptor)
Rob Pikeaf82b4e2010-04-30 15:19:25 -070072}
73
74var plugins []Plugin
75
76// RegisterPlugin installs a (second-order) plugin to be run when the Go output is generated.
77// It is typically called during initialization.
78func RegisterPlugin(p Plugin) {
David Symondscc7142e2010-11-06 14:37:15 +110079 plugins = append(plugins, p)
Rob Pikeaf82b4e2010-04-30 15:19:25 -070080}
81
82// Each type we import as a protocol buffer (other than FileDescriptorProto) needs
83// a pointer to the FileDescriptorProto that represents it. These types achieve that
84// wrapping by placing each Proto inside a struct with the pointer to its File. The
85// structs have the same names as their contents, with "Proto" removed.
86// FileDescriptor is used to store the things that it points to.
87
88// The file and package name method are common to messages and enums.
89type common struct {
David Symonds4decd802011-08-04 11:27:07 +100090 file *descriptor.FileDescriptorProto // File this object comes from.
Rob Pikeaf82b4e2010-04-30 15:19:25 -070091}
92
93// PackageName is name in the package clause in the generated file.
David Symonds4decd802011-08-04 11:27:07 +100094func (c *common) PackageName() string { return uniquePackageOf(c.file) }
95
96func (c *common) File() *descriptor.FileDescriptorProto { return c.file }
Rob Pikeaf82b4e2010-04-30 15:19:25 -070097
98// Descriptor represents a protocol buffer message.
99type Descriptor struct {
100 common
101 *descriptor.DescriptorProto
102 parent *Descriptor // The containing message, if any.
103 nested []*Descriptor // Inner messages, if any.
104 ext []*ExtensionDescriptor // Extensions, if any.
105 typename []string // Cached typename vector.
David Symonds4de8f722012-09-26 13:51:38 +1000106 index int // If a top-level message, the index into message_type.
David Symonds6eaeef12012-11-07 11:42:56 +1100107 group bool
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700108}
109
110// TypeName returns the elements of the dotted type name.
111// The package name is not part of this name.
112func (d *Descriptor) TypeName() []string {
113 if d.typename != nil {
114 return d.typename
115 }
116 n := 0
117 for parent := d; parent != nil; parent = parent.parent {
118 n++
119 }
120 s := make([]string, n, n)
121 for parent := d; parent != nil; parent = parent.parent {
122 n--
David Symonds8bb32ca2012-06-28 10:22:09 -0700123 s[n] = parent.GetName()
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700124 }
125 d.typename = s
126 return s
127}
128
129// EnumDescriptor describes an enum. If it's at top level, its parent will be nil.
130// Otherwise it will be the descriptor of the message in which it is defined.
131type EnumDescriptor struct {
132 common
133 *descriptor.EnumDescriptorProto
134 parent *Descriptor // The containing message, if any.
135 typename []string // Cached typename vector.
136}
137
138// TypeName returns the elements of the dotted type name.
139// The package name is not part of this name.
140func (e *EnumDescriptor) TypeName() (s []string) {
141 if e.typename != nil {
142 return e.typename
143 }
David Symonds8bb32ca2012-06-28 10:22:09 -0700144 name := e.GetName()
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700145 if e.parent == nil {
146 s = make([]string, 1)
147 } else {
148 pname := e.parent.TypeName()
149 s = make([]string, len(pname)+1)
150 copy(s, pname)
151 }
152 s[len(s)-1] = name
153 e.typename = s
154 return s
155}
156
157// Everything but the last element of the full type name, CamelCased.
158// The values of type Foo.Bar are call Foo_value1... not Foo_Bar_value1... .
159func (e *EnumDescriptor) prefix() string {
160 typeName := e.TypeName()
161 ccPrefix := CamelCaseSlice(typeName[0:len(typeName)-1]) + "_"
162 if e.parent == nil {
163 // If the enum is not part of a message, the prefix is just the type name.
164 ccPrefix = CamelCase(*e.Name) + "_"
165 }
166 return ccPrefix
167}
168
169// The integer value of the named constant in this enumerated type.
170func (e *EnumDescriptor) integerValueAsString(name string) string {
171 for _, c := range e.Value {
David Symonds8bb32ca2012-06-28 10:22:09 -0700172 if c.GetName() == name {
173 return fmt.Sprint(c.GetNumber())
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700174 }
175 }
David Symonds9d0000e2011-02-03 10:48:14 +1100176 log.Fatal("cannot find value for enum constant")
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700177 return ""
178}
179
David Symonds4decd802011-08-04 11:27:07 +1000180// ExtensionDescriptor describes an extension. If it's at top level, its parent will be nil.
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700181// Otherwise it will be the descriptor of the message in which it is defined.
182type ExtensionDescriptor struct {
183 common
184 *descriptor.FieldDescriptorProto
Rob Pikec9e7d972010-06-10 10:30:22 -0700185 parent *Descriptor // The containing message, if any.
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700186}
187
188// TypeName returns the elements of the dotted type name.
189// The package name is not part of this name.
190func (e *ExtensionDescriptor) TypeName() (s []string) {
David Symonds8bb32ca2012-06-28 10:22:09 -0700191 name := e.GetName()
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700192 if e.parent == nil {
193 // top-level extension
194 s = make([]string, 1)
195 } else {
196 pname := e.parent.TypeName()
197 s = make([]string, len(pname)+1)
198 copy(s, pname)
199 }
200 s[len(s)-1] = name
201 return s
202}
203
David Symondse37856c2011-06-22 12:52:53 +1000204// DescName returns the variable name used for the generated descriptor.
205func (e *ExtensionDescriptor) DescName() string {
206 // The full type name.
207 typeName := e.TypeName()
208 // Each scope of the extension is individually CamelCased, and all are joined with "_" with an "E_" prefix.
209 for i, s := range typeName {
210 typeName[i] = CamelCase(s)
211 }
212 return "E_" + strings.Join(typeName, "_")
213}
214
David Symonds4decd802011-08-04 11:27:07 +1000215// ImportedDescriptor describes a type that has been publicly imported from another file.
216type ImportedDescriptor struct {
217 common
218 o Object
219}
220
221func (id *ImportedDescriptor) TypeName() []string { return id.o.TypeName() }
222
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700223// FileDescriptor describes an protocol buffer descriptor file (.proto).
224// It includes slices of all the messages and enums defined within it.
225// Those slices are constructed by WrapTypes.
226type FileDescriptor struct {
227 *descriptor.FileDescriptorProto
Rob Pikec9e7d972010-06-10 10:30:22 -0700228 desc []*Descriptor // All the messages defined in this file.
229 enum []*EnumDescriptor // All the enums defined in this file.
230 ext []*ExtensionDescriptor // All the top-level extensions defined in this file.
David Symonds4decd802011-08-04 11:27:07 +1000231 imp []*ImportedDescriptor // All types defined in files publicly imported by this file.
David Symonds31d58a22011-01-20 18:33:21 +1100232
David Symondsb2a00c82011-08-04 16:52:58 +1000233 // The full list of symbols that are exported,
234 // as a map from the exported object to its symbols.
David Symonds31d58a22011-01-20 18:33:21 +1100235 // This is used for supporting public imports.
David Symonds151cce02012-12-06 13:34:42 +1100236 exported map[Object][]symbol
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700237}
238
239// PackageName is the package name we'll use in the generated code to refer to this file.
240func (d *FileDescriptor) PackageName() string { return uniquePackageOf(d.FileDescriptorProto) }
241
David Symonds162d0032012-06-28 09:44:46 -0700242// goPackageName returns the Go package name to use in the
243// generated Go file. The result explicit reports whether the name
244// came from an option go_package statement. If explicit is false,
245// the name was derived from the protocol buffer's package statement
246// or the input file name.
247func (d *FileDescriptor) goPackageName() (name string, explicit bool) {
248
Rob Pikec9e7d972010-06-10 10:30:22 -0700249 // Does the file have a package clause?
David Symonds8bb32ca2012-06-28 10:22:09 -0700250 if pkg := d.GetPackage(); pkg != "" {
David Symonds162d0032012-06-28 09:44:46 -0700251 return pkg, false
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700252 }
Rob Pikec9e7d972010-06-10 10:30:22 -0700253 // Use the file base name.
David Symonds151cce02012-12-06 13:34:42 +1100254 return baseName(d.GetName()), false
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700255}
256
David Symonds151cce02012-12-06 13:34:42 +1100257func (d *FileDescriptor) addExport(obj Object, sym symbol) {
258 d.exported[obj] = append(d.exported[obj], sym)
David Symonds31d58a22011-01-20 18:33:21 +1100259}
260
David Symonds151cce02012-12-06 13:34:42 +1100261// symbol is an interface representing an exported Go symbol.
262type symbol interface {
David Symonds31d58a22011-01-20 18:33:21 +1100263 // GenerateAlias should generate an appropriate alias
264 // for the symbol from the named package.
265 GenerateAlias(g *Generator, pkg string)
266}
267
268type messageSymbol struct {
269 sym string
270 hasExtensions, isMessageSet bool
David Symonds381349d2012-09-18 15:11:46 +1000271 getters []getterSymbol
David Symonds31d58a22011-01-20 18:33:21 +1100272}
273
David Symonds381349d2012-09-18 15:11:46 +1000274type getterSymbol struct {
275 name string
276 typ string
277 typeName string // canonical name in proto world; empty for proto.Message and similar
278 genType bool // whether typ is a generated type (message/group/enum)
279}
280
281func (ms *messageSymbol) GenerateAlias(g *Generator, pkg string) {
David Symonds31d58a22011-01-20 18:33:21 +1100282 remoteSym := pkg + "." + ms.sym
283
284 g.P("type ", ms.sym, " ", remoteSym)
285 g.P("func (this *", ms.sym, ") Reset() { (*", remoteSym, ")(this).Reset() }")
David Symondse37856c2011-06-22 12:52:53 +1000286 g.P("func (this *", ms.sym, ") String() string { return (*", remoteSym, ")(this).String() }")
David Symonds9f60f432012-06-14 09:45:25 +1000287 g.P("func (*", ms.sym, ") ProtoMessage() {}")
David Symonds31d58a22011-01-20 18:33:21 +1100288 if ms.hasExtensions {
David Symonds11db5982012-08-15 10:54:05 +1000289 g.P("func (*", ms.sym, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange ",
David Symonds31d58a22011-01-20 18:33:21 +1100290 "{ return (*", remoteSym, ")(nil).ExtensionRangeArray() }")
David Symonds11db5982012-08-15 10:54:05 +1000291 g.P("func (this *", ms.sym, ") ExtensionMap() map[int32]", g.Pkg["proto"], ".Extension ",
David Symonds31d58a22011-01-20 18:33:21 +1100292 "{ return (*", remoteSym, ")(this).ExtensionMap() }")
293 if ms.isMessageSet {
Rob Pikea17fdd92011-11-02 12:43:05 -0700294 g.P("func (this *", ms.sym, ") Marshal() ([]byte, error) ",
David Symonds31d58a22011-01-20 18:33:21 +1100295 "{ return (*", remoteSym, ")(this).Marshal() }")
Rob Pikea17fdd92011-11-02 12:43:05 -0700296 g.P("func (this *", ms.sym, ") Unmarshal(buf []byte) error ",
David Symonds31d58a22011-01-20 18:33:21 +1100297 "{ return (*", remoteSym, ")(this).Unmarshal(buf) }")
298 }
299 }
David Symonds381349d2012-09-18 15:11:46 +1000300 for _, get := range ms.getters {
301 typ := get.typ
302 val := "(*" + remoteSym + ")(this)." + get.name + "()"
303 if get.genType {
304 // typ will be "*pkg.T" (message/group) or "pkg.T" (enum).
305 // Drop the package qualifier since we have hoisted the type into this package.
306 star := typ[0] == '*'
307 typ = typ[strings.Index(typ, ".")+1:]
308 if star {
309 typ = "*" + typ
310 }
311 // Convert imported type into the forwarding type.
312 val = "(" + typ + ")(" + val + ")"
313 }
314
315 g.P("func (this *", ms.sym, ") ", get.name, "() ", typ, " { return ", val, " }")
316 if get.typeName != "" {
317 g.RecordTypeUse(get.typeName)
318 }
319 }
David Symonds31d58a22011-01-20 18:33:21 +1100320}
321
322type enumSymbol string
323
324func (es enumSymbol) GenerateAlias(g *Generator, pkg string) {
325 s := string(es)
326 g.P("type ", s, " ", pkg, ".", s)
327 g.P("var ", s, "_name = ", pkg, ".", s, "_name")
328 g.P("var ", s, "_value = ", pkg, ".", s, "_value")
David Symondsdd9ca042011-08-29 16:07:16 +1000329 g.P("func New", s, "(x ", s, ") *", s, " { e := ", s, "(x); return &e }")
David Symonds31d58a22011-01-20 18:33:21 +1100330}
331
332type constOrVarSymbol struct {
333 sym string
334 typ string // either "const" or "var"
335}
336
337func (cs constOrVarSymbol) GenerateAlias(g *Generator, pkg string) {
338 g.P(cs.typ, " ", cs.sym, " = ", pkg, ".", cs.sym)
339}
340
David Symonds4decd802011-08-04 11:27:07 +1000341// Object is an interface abstracting the abilities shared by enums, messages, extensions and imported objects.
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700342type Object interface {
343 PackageName() string // The name we use in our output (a_b_c), possibly renamed for uniqueness.
344 TypeName() []string
David Symonds4decd802011-08-04 11:27:07 +1000345 File() *descriptor.FileDescriptorProto
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700346}
347
348// Each package name we generate must be unique. The package we're generating
David Symonds4decd802011-08-04 11:27:07 +1000349// gets its own name but every other package must have a unique name that does
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700350// not conflict in the code we generate. These names are chosen globally (although
351// they don't have to be, it simplifies things to do them globally).
352func uniquePackageOf(fd *descriptor.FileDescriptorProto) string {
353 s, ok := uniquePackageName[fd]
354 if !ok {
David Symondsd4661c52012-08-30 15:17:53 +1000355 log.Fatal("internal error: no package name defined for " + fd.GetName())
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700356 }
357 return s
358}
359
360// Generator is the type whose methods generate the output, stored in the associated response structure.
361type Generator struct {
David Symondsf90e3382010-05-05 10:53:44 +1000362 *bytes.Buffer
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700363
364 Request *plugin.CodeGeneratorRequest // The input.
365 Response *plugin.CodeGeneratorResponse // The output.
366
David Symonds162d0032012-06-28 09:44:46 -0700367 Param map[string]string // Command-line parameters.
368 PackageImportPath string // Go import path of the package we're generating code for
369 ImportPrefix string // String to prefix to imported package file names.
370 ImportMap map[string]string // Mapping from import name to generated name
Rob Pikec9e7d972010-06-10 10:30:22 -0700371
David Symonds11db5982012-08-15 10:54:05 +1000372 Pkg map[string]string // The names under which we import support packages
Rob Pikec9e7d972010-06-10 10:30:22 -0700373
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700374 packageName string // What we're calling ourselves.
375 allFiles []*FileDescriptor // All files in the tree
376 genFiles []*FileDescriptor // Those files we will generate output for.
377 file *FileDescriptor // The file we are compiling now.
David Symondsf90e3382010-05-05 10:53:44 +1000378 usedPackages map[string]bool // Names of packages used in current file.
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700379 typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax.
380 indent string
381}
382
383// New creates a new generator and allocates the request and response protobufs.
384func New() *Generator {
385 g := new(Generator)
David Symondsf90e3382010-05-05 10:53:44 +1000386 g.Buffer = new(bytes.Buffer)
David Symondsb0127532010-11-09 11:10:46 +1100387 g.Request = new(plugin.CodeGeneratorRequest)
388 g.Response = new(plugin.CodeGeneratorResponse)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700389 return g
390}
391
Rob Pikea17fdd92011-11-02 12:43:05 -0700392// Error reports a problem, including an error, and exits the program.
393func (g *Generator) Error(err error, msgs ...string) {
394 s := strings.Join(msgs, " ") + ":" + err.Error()
David Symondsd4661c52012-08-30 15:17:53 +1000395 log.Print("protoc-gen-go: error:", s)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700396 os.Exit(1)
397}
398
399// Fail reports a problem and exits the program.
400func (g *Generator) Fail(msgs ...string) {
401 s := strings.Join(msgs, " ")
David Symondsd4661c52012-08-30 15:17:53 +1000402 log.Print("protoc-gen-go: error:", s)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700403 os.Exit(1)
404}
405
Rob Pikec9e7d972010-06-10 10:30:22 -0700406// CommandLineParameters breaks the comma-separated list of key=value pairs
407// in the parameter (a member of the request protobuf) into a key/value map.
408// It then sets file name mappings defined by those entries.
409func (g *Generator) CommandLineParameters(parameter string) {
410 g.Param = make(map[string]string)
David Symonds8935abf2011-07-04 15:53:16 +1000411 for _, p := range strings.Split(parameter, ",") {
Rob Pikec9e7d972010-06-10 10:30:22 -0700412 if i := strings.Index(p, "="); i < 0 {
413 g.Param[p] = ""
414 } else {
415 g.Param[p[0:i]] = p[i+1:]
416 }
417 }
418
419 g.ImportMap = make(map[string]string)
420 for k, v := range g.Param {
David Symonds162d0032012-06-28 09:44:46 -0700421 switch k {
422 case "import_prefix":
Rob Pikec9e7d972010-06-10 10:30:22 -0700423 g.ImportPrefix = v
David Symondse90896d2012-08-15 11:18:55 +1000424 case "import_path":
David Symonds162d0032012-06-28 09:44:46 -0700425 g.PackageImportPath = v
426 default:
427 if len(k) > 0 && k[0] == 'M' {
428 g.ImportMap[k[1:]] = v
429 }
Rob Pikec9e7d972010-06-10 10:30:22 -0700430 }
431 }
432}
433
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700434// DefaultPackageName returns the package name printed for the object.
435// If its file is in a different package, it returns the package name we're using for this file, plus ".".
436// Otherwise it returns the empty string.
437func (g *Generator) DefaultPackageName(obj Object) string {
438 pkg := obj.PackageName()
439 if pkg == g.packageName {
440 return ""
441 }
442 return pkg + "."
443}
444
445// For each input file, the unique package name to use, underscored.
446var uniquePackageName = make(map[*descriptor.FileDescriptorProto]string)
Rob Pike3f6f2d82011-12-18 13:55:35 -0800447
Rob Pikec9e7d972010-06-10 10:30:22 -0700448// Package names already registered. Key is the name from the .proto file;
449// value is the name that appears in the generated code.
450var pkgNamesInUse = make(map[string]bool)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700451
Rob Pikec9e7d972010-06-10 10:30:22 -0700452// Create and remember a guaranteed unique package name for this file descriptor.
453// Pkg is the candidate name. If f is nil, it's a builtin package like "proto" and
454// has no file descriptor.
455func RegisterUniquePackageName(pkg string, f *FileDescriptor) string {
David Symonds41389812011-07-19 14:57:40 +1000456 // Convert dots to underscores before finding a unique alias.
David Symonds151cce02012-12-06 13:34:42 +1100457 pkg = strings.Map(badToUnderscore, pkg)
David Symonds41389812011-07-19 14:57:40 +1000458
David Symonds79eae332010-10-16 11:33:20 +1100459 for i, orig := 1, pkg; pkgNamesInUse[pkg]; i++ {
Rob Pikec9e7d972010-06-10 10:30:22 -0700460 // It's a duplicate; must rename.
David Symonds79eae332010-10-16 11:33:20 +1100461 pkg = orig + strconv.Itoa(i)
Rob Pikec9e7d972010-06-10 10:30:22 -0700462 }
463 // Install it.
464 pkgNamesInUse[pkg] = true
Rob Pikec9e7d972010-06-10 10:30:22 -0700465 if f != nil {
466 uniquePackageName[f.FileDescriptorProto] = pkg
467 }
468 return pkg
469}
470
David Symonds162d0032012-06-28 09:44:46 -0700471var isGoKeyword = map[string]bool{
472 "break": true,
473 "case": true,
474 "chan": true,
475 "const": true,
476 "continue": true,
477 "default": true,
478 "else": true,
479 "defer": true,
480 "fallthrough": true,
481 "for": true,
482 "func": true,
483 "go": true,
484 "goto": true,
485 "if": true,
486 "import": true,
487 "interface": true,
488 "map": true,
489 "package": true,
490 "range": true,
491 "return": true,
492 "select": true,
493 "struct": true,
494 "switch": true,
495 "type": true,
496 "var": true,
497}
498
499// defaultGoPackage returns the package name to use,
500// derived from the import path of the package we're building code for.
501func (g *Generator) defaultGoPackage() string {
502 p := g.PackageImportPath
503 if i := strings.LastIndex(p, "/"); i >= 0 {
504 p = p[i+1:]
505 }
506 if p == "" {
507 return ""
508 }
509
David Symonds151cce02012-12-06 13:34:42 +1100510 p = strings.Map(badToUnderscore, p)
David Symonds162d0032012-06-28 09:44:46 -0700511 // Identifier must not be keyword: insert _.
512 if isGoKeyword[p] {
513 p = "_" + p
514 }
515 // Identifier must not begin with digit: insert _.
516 if r, _ := utf8.DecodeRuneInString(p); unicode.IsDigit(r) {
517 p = "_" + p
518 }
519 return p
520}
521
Rob Pikec9e7d972010-06-10 10:30:22 -0700522// SetPackageNames sets the package name for this run.
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700523// The package name must agree across all files being generated.
524// It also defines unique package names for all imported files.
525func (g *Generator) SetPackageNames() {
Rob Pikec9e7d972010-06-10 10:30:22 -0700526 // Register the name for this package. It will be the first name
527 // registered so is guaranteed to be unmodified.
David Symonds162d0032012-06-28 09:44:46 -0700528 pkg, explicit := g.genFiles[0].goPackageName()
529
530 // Check all files for an explicit go_package option.
531 for _, f := range g.genFiles {
532 thisPkg, thisExplicit := f.goPackageName()
533 if thisExplicit {
534 if !explicit {
535 // Let this file's go_package option serve for all input files.
536 pkg, explicit = thisPkg, true
537 } else if thisPkg != pkg {
538 g.Fail("inconsistent package names:", thisPkg, pkg)
539 }
540 }
541 }
542
543 // If we don't have an explicit go_package option but we have an
544 // import path, use that.
545 if !explicit {
546 p := g.defaultGoPackage()
547 if p != "" {
548 pkg, explicit = p, true
549 }
550 }
551
552 // If there was no go_package and no import path to use,
553 // double-check that all the inputs have the same implicit
554 // Go package name.
555 if !explicit {
556 for _, f := range g.genFiles {
557 thisPkg, _ := f.goPackageName()
558 if thisPkg != pkg {
559 g.Fail("inconsistent package names:", thisPkg, pkg)
560 }
561 }
562 }
563
Rob Pikec9e7d972010-06-10 10:30:22 -0700564 g.packageName = RegisterUniquePackageName(pkg, g.genFiles[0])
David Symonds162d0032012-06-28 09:44:46 -0700565
David Symonds11db5982012-08-15 10:54:05 +1000566 // Register the support package names. They might collide with the
Rob Pikec9e7d972010-06-10 10:30:22 -0700567 // name of a package we import.
David Symonds11db5982012-08-15 10:54:05 +1000568 g.Pkg = map[string]string{
569 "json": RegisterUniquePackageName("json", nil),
570 "math": RegisterUniquePackageName("math", nil),
571 "proto": RegisterUniquePackageName("proto", nil),
572 }
David Symonds162d0032012-06-28 09:44:46 -0700573
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700574AllFiles:
575 for _, f := range g.allFiles {
576 for _, genf := range g.genFiles {
577 if f == genf {
578 // In this package already.
579 uniquePackageName[f.FileDescriptorProto] = g.packageName
580 continue AllFiles
581 }
582 }
David Symonds7d5c8242011-03-14 12:03:50 -0700583 // The file is a dependency, so we want to ignore its go_package option
584 // because that is only relevant for its specific generated output.
David Symonds8bb32ca2012-06-28 10:22:09 -0700585 pkg := f.GetPackage()
David Symonds7d5c8242011-03-14 12:03:50 -0700586 if pkg == "" {
David Symonds151cce02012-12-06 13:34:42 +1100587 pkg = baseName(*f.Name)
David Symonds7d5c8242011-03-14 12:03:50 -0700588 }
589 RegisterUniquePackageName(pkg, f)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700590 }
591}
592
593// WrapTypes walks the incoming data, wrapping DescriptorProtos, EnumDescriptorProtos
594// and FileDescriptorProtos into file-referenced objects within the Generator.
595// It also creates the list of files to generate and so should be called before GenerateAllFiles.
596func (g *Generator) WrapTypes() {
597 g.allFiles = make([]*FileDescriptor, len(g.Request.ProtoFile))
598 for i, f := range g.Request.ProtoFile {
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700599 // We must wrap the descriptors before we wrap the enums
600 descs := wrapDescriptors(f)
601 g.buildNestedDescriptors(descs)
602 enums := wrapEnumDescriptors(f, descs)
603 exts := wrapExtensions(f)
David Symonds4decd802011-08-04 11:27:07 +1000604 imps := wrapImported(f, g)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700605 g.allFiles[i] = &FileDescriptor{
606 FileDescriptorProto: f,
607 desc: descs,
608 enum: enums,
609 ext: exts,
David Symonds4decd802011-08-04 11:27:07 +1000610 imp: imps,
David Symonds151cce02012-12-06 13:34:42 +1100611 exported: make(map[Object][]symbol),
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700612 }
613 }
614
615 g.genFiles = make([]*FileDescriptor, len(g.Request.FileToGenerate))
616FindFiles:
617 for i, fileName := range g.Request.FileToGenerate {
618 // Search the list. This algorithm is n^2 but n is tiny.
619 for _, file := range g.allFiles {
David Symonds8bb32ca2012-06-28 10:22:09 -0700620 if fileName == file.GetName() {
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700621 g.genFiles[i] = file
622 continue FindFiles
623 }
624 }
625 g.Fail("could not find file named", fileName)
626 }
627 g.Response.File = make([]*plugin.CodeGeneratorResponse_File, len(g.genFiles))
628}
629
630// Scan the descriptors in this file. For each one, build the slice of nested descriptors
631func (g *Generator) buildNestedDescriptors(descs []*Descriptor) {
632 for _, desc := range descs {
633 if len(desc.NestedType) != 0 {
634 desc.nested = make([]*Descriptor, len(desc.NestedType))
635 n := 0
636 for _, nest := range descs {
637 if nest.parent == desc {
638 desc.nested[n] = nest
639 n++
640 }
641 }
642 if n != len(desc.NestedType) {
David Symonds8bb32ca2012-06-28 10:22:09 -0700643 g.Fail("internal error: nesting failure for", desc.GetName())
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700644 }
645 }
646 }
647}
648
649// Construct the Descriptor and add it to the slice
David Symonds4de8f722012-09-26 13:51:38 +1000650func addDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto, index int) []*Descriptor {
David Symonds6eaeef12012-11-07 11:42:56 +1100651 d := &Descriptor{common{file}, desc, parent, nil, nil, nil, index, false}
652
653 // The only way to distinguish a group from a message is whether
654 // the containing message has a TYPE_GROUP field that matches.
655 if parent != nil {
656 parts := d.TypeName()
657 if file.Package != nil {
658 parts = append([]string{*file.Package}, parts...)
659 }
660 exp := "." + strings.Join(parts, ".")
661 for _, field := range parent.Field {
662 if field.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP && field.GetTypeName() == exp {
663 d.group = true
664 break
665 }
666 }
667 }
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700668
669 d.ext = make([]*ExtensionDescriptor, len(desc.Extension))
670 for i, field := range desc.Extension {
David Symonds4decd802011-08-04 11:27:07 +1000671 d.ext[i] = &ExtensionDescriptor{common{file}, field, d}
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700672 }
673
David Symondscc7142e2010-11-06 14:37:15 +1100674 return append(sl, d)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700675}
676
677// Return a slice of all the Descriptors defined within this file
678func wrapDescriptors(file *descriptor.FileDescriptorProto) []*Descriptor {
679 sl := make([]*Descriptor, 0, len(file.MessageType)+10)
David Symonds4de8f722012-09-26 13:51:38 +1000680 for i, desc := range file.MessageType {
681 sl = wrapThisDescriptor(sl, desc, nil, file, i)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700682 }
683 return sl
684}
685
686// Wrap this Descriptor, recursively
David Symonds4de8f722012-09-26 13:51:38 +1000687func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto, index int) []*Descriptor {
688 sl = addDescriptor(sl, desc, parent, file, index)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700689 me := sl[len(sl)-1]
690 for _, nested := range desc.NestedType {
David Symonds4de8f722012-09-26 13:51:38 +1000691 sl = wrapThisDescriptor(sl, nested, me, file, 0)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700692 }
693 return sl
694}
695
696// Construct the EnumDescriptor and add it to the slice
697func addEnumDescriptor(sl []*EnumDescriptor, desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*EnumDescriptor {
David Symonds4decd802011-08-04 11:27:07 +1000698 return append(sl, &EnumDescriptor{common{file}, desc, parent, nil})
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700699}
700
701// Return a slice of all the EnumDescriptors defined within this file
702func wrapEnumDescriptors(file *descriptor.FileDescriptorProto, descs []*Descriptor) []*EnumDescriptor {
703 sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
David Symonds5256cf62010-06-27 10:33:42 +1000704 // Top-level enums.
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700705 for _, enum := range file.EnumType {
706 sl = addEnumDescriptor(sl, enum, nil, file)
707 }
David Symonds5256cf62010-06-27 10:33:42 +1000708 // Enums within messages. Enums within embedded messages appear in the outer-most message.
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700709 for _, nested := range descs {
David Symonds5256cf62010-06-27 10:33:42 +1000710 for _, enum := range nested.EnumType {
711 sl = addEnumDescriptor(sl, enum, nested, file)
712 }
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700713 }
714 return sl
715}
716
717// Return a slice of all the top-level ExtensionDescriptors defined within this file.
718func wrapExtensions(file *descriptor.FileDescriptorProto) []*ExtensionDescriptor {
719 sl := make([]*ExtensionDescriptor, len(file.Extension))
720 for i, field := range file.Extension {
David Symonds4decd802011-08-04 11:27:07 +1000721 sl[i] = &ExtensionDescriptor{common{file}, field, nil}
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700722 }
723 return sl
724}
725
David Symonds4decd802011-08-04 11:27:07 +1000726// Return a slice of all the types that are publicly imported into this file.
727func wrapImported(file *descriptor.FileDescriptorProto, g *Generator) (sl []*ImportedDescriptor) {
728 for _, index := range file.PublicDependency {
729 df := g.fileByName(file.Dependency[index])
730 for _, d := range df.desc {
731 sl = append(sl, &ImportedDescriptor{common{file}, d})
732 }
733 for _, e := range df.enum {
734 sl = append(sl, &ImportedDescriptor{common{file}, e})
735 }
736 for _, ext := range df.ext {
737 sl = append(sl, &ImportedDescriptor{common{file}, ext})
738 }
739 }
740 return
741}
742
Rob Pikec9e7d972010-06-10 10:30:22 -0700743// BuildTypeNameMap builds the map from fully qualified type names to objects.
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700744// The key names for the map come from the input data, which puts a period at the beginning.
745// It should be called after SetPackageNames and before GenerateAllFiles.
746func (g *Generator) BuildTypeNameMap() {
747 g.typeNameToObject = make(map[string]Object)
748 for _, f := range g.allFiles {
Rob Pikec9e7d972010-06-10 10:30:22 -0700749 // The names in this loop are defined by the proto world, not us, so the
750 // package name may be empty. If so, the dotted package name of X will
751 // be ".X"; otherwise it will be ".pkg.X".
David Symonds8bb32ca2012-06-28 10:22:09 -0700752 dottedPkg := "." + f.GetPackage()
Rob Pikec9e7d972010-06-10 10:30:22 -0700753 if dottedPkg != "." {
754 dottedPkg += "."
755 }
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700756 for _, enum := range f.enum {
757 name := dottedPkg + dottedSlice(enum.TypeName())
758 g.typeNameToObject[name] = enum
759 }
760 for _, desc := range f.desc {
761 name := dottedPkg + dottedSlice(desc.TypeName())
762 g.typeNameToObject[name] = desc
763 }
764 }
765}
766
767// ObjectNamed, given a fully-qualified input type name as it appears in the input data,
768// returns the descriptor for the message or enum with that name.
769func (g *Generator) ObjectNamed(typeName string) Object {
David Symonds4decd802011-08-04 11:27:07 +1000770 o, ok := g.typeNameToObject[typeName]
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700771 if !ok {
772 g.Fail("can't find object with type", typeName)
773 }
David Symonds4decd802011-08-04 11:27:07 +1000774
775 // If the file of this object isn't a direct dependency of the current file,
776 // or in the current file, then this object has been publicly imported into
777 // a dependency of the current file.
778 // We should return the ImportedDescriptor object for it instead.
779 direct := *o.File().Name == *g.file.Name
780 if !direct {
781 for _, dep := range g.file.Dependency {
782 if *g.fileByName(dep).Name == *o.File().Name {
783 direct = true
784 break
785 }
786 }
787 }
788 if !direct {
789 found := false
790 Loop:
791 for _, dep := range g.file.Dependency {
792 df := g.fileByName(*g.fileByName(dep).Name)
793 for _, td := range df.imp {
794 if td.o == o {
795 // Found it!
796 o = td
797 found = true
798 break Loop
799 }
800 }
801 }
802 if !found {
803 log.Printf("protoc-gen-go: WARNING: failed finding publicly imported dependency for %v, used in %v", typeName, *g.file.Name)
804 }
805 }
806
807 return o
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700808}
809
810// P prints the arguments to the generated output. It handles strings and int32s, plus
811// handling indirections because they may be *string, etc.
812func (g *Generator) P(str ...interface{}) {
813 g.WriteString(g.indent)
814 for _, v := range str {
815 switch s := v.(type) {
816 case string:
817 g.WriteString(s)
818 case *string:
819 g.WriteString(*s)
Rob Pikec9e7d972010-06-10 10:30:22 -0700820 case bool:
821 g.WriteString(fmt.Sprintf("%t", s))
822 case *bool:
823 g.WriteString(fmt.Sprintf("%t", *s))
David Symonds4de8f722012-09-26 13:51:38 +1000824 case int:
825 g.WriteString(fmt.Sprintf("%d", s))
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700826 case *int32:
827 g.WriteString(fmt.Sprintf("%d", *s))
Rob Pikec9e7d972010-06-10 10:30:22 -0700828 case float64:
829 g.WriteString(fmt.Sprintf("%g", s))
830 case *float64:
831 g.WriteString(fmt.Sprintf("%g", *s))
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700832 default:
833 g.Fail(fmt.Sprintf("unknown type in printer: %T", v))
834 }
835 }
836 g.WriteByte('\n')
837}
838
839// In Indents the output one tab stop.
840func (g *Generator) In() { g.indent += "\t" }
841
842// Out unindents the output one tab stop.
843func (g *Generator) Out() {
844 if len(g.indent) > 0 {
845 g.indent = g.indent[1:]
846 }
847}
848
849// GenerateAllFiles generates the output for all the files we're outputting.
850func (g *Generator) GenerateAllFiles() {
Rob Pikec9e7d972010-06-10 10:30:22 -0700851 // Initialize the plugins
852 for _, p := range plugins {
853 p.Init(g)
854 }
David Symonds31d58a22011-01-20 18:33:21 +1100855 // Generate the output. The generator runs for every file, even the files
856 // that we don't generate output for, so that we can collate the full list
857 // of exported symbols to support public imports.
858 genFileMap := make(map[*FileDescriptor]bool, len(g.genFiles))
859 for _, file := range g.genFiles {
860 genFileMap[file] = true
861 }
862 i := 0
863 for _, file := range g.allFiles {
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700864 g.Reset()
865 g.generate(file)
David Symonds31d58a22011-01-20 18:33:21 +1100866 if _, ok := genFileMap[file]; !ok {
867 continue
868 }
David Symondsb0127532010-11-09 11:10:46 +1100869 g.Response.File[i] = new(plugin.CodeGeneratorResponse_File)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700870 g.Response.File[i].Name = proto.String(goFileName(*file.Name))
871 g.Response.File[i].Content = proto.String(g.String())
David Symonds31d58a22011-01-20 18:33:21 +1100872 i++
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700873 }
874}
875
876// Run all the plugins associated with the file.
877func (g *Generator) runPlugins(file *FileDescriptor) {
878 for _, p := range plugins {
Rob Pikec9e7d972010-06-10 10:30:22 -0700879 p.Generate(file)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700880 }
881}
882
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700883// FileOf return the FileDescriptor for this FileDescriptorProto.
884func (g *Generator) FileOf(fd *descriptor.FileDescriptorProto) *FileDescriptor {
885 for _, file := range g.allFiles {
886 if file.FileDescriptorProto == fd {
887 return file
888 }
889 }
David Symonds8bb32ca2012-06-28 10:22:09 -0700890 g.Fail("could not find file in table:", fd.GetName())
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700891 return nil
892}
893
894// Fill the response protocol buffer with the generated output for all the files we're
895// supposed to generate.
896func (g *Generator) generate(file *FileDescriptor) {
897 g.file = g.FileOf(file.FileDescriptorProto)
David Symondsf90e3382010-05-05 10:53:44 +1000898 g.usedPackages = make(map[string]bool)
899
David Symonds4decd802011-08-04 11:27:07 +1000900 for _, td := range g.file.imp {
901 g.generateImported(td)
902 }
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700903 for _, enum := range g.file.enum {
904 g.generateEnum(enum)
905 }
906 for _, desc := range g.file.desc {
907 g.generateMessage(desc)
908 }
909 for _, ext := range g.file.ext {
910 g.generateExtension(ext)
911 }
912 g.generateInitFunction()
David Symondsf90e3382010-05-05 10:53:44 +1000913
Rob Pikec9e7d972010-06-10 10:30:22 -0700914 // Run the plugins before the imports so we know which imports are necessary.
915 g.runPlugins(file)
916
David Symondsf90e3382010-05-05 10:53:44 +1000917 // Generate header and imports last, though they appear first in the output.
918 rem := g.Buffer
919 g.Buffer = new(bytes.Buffer)
920 g.generateHeader()
921 g.generateImports()
922 g.Write(rem.Bytes())
David Symondsb1d55a02011-04-08 09:55:06 +1000923
924 // Reformat generated code.
925 fset := token.NewFileSet()
926 ast, err := parser.ParseFile(fset, "", g, parser.ParseComments)
927 if err != nil {
Rob Pikea17fdd92011-11-02 12:43:05 -0700928 g.Fail("bad Go source code was generated:", err.Error())
David Symondsb1d55a02011-04-08 09:55:06 +1000929 return
930 }
931 g.Reset()
David Symonds5ed980c2011-11-29 09:52:21 +1100932 err = (&printer.Config{printer.TabIndent | printer.UseSpaces, 8}).Fprint(g, fset, ast)
David Symondsb1d55a02011-04-08 09:55:06 +1000933 if err != nil {
Rob Pikea17fdd92011-11-02 12:43:05 -0700934 g.Fail("generated Go source code could not be reformatted:", err.Error())
David Symondsb1d55a02011-04-08 09:55:06 +1000935 }
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700936}
937
David Symonds62539862012-08-04 10:06:55 +1000938// Generate the header, including package definition
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700939func (g *Generator) generateHeader() {
David Symondsd4661c52012-08-30 15:17:53 +1000940 g.P("// Code generated by protoc-gen-go.")
941 g.P("// source: ", *g.file.Name)
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700942 g.P("// DO NOT EDIT!")
943 g.P()
944 g.P("package ", g.file.PackageName())
945 g.P()
946}
947
David Symonds31d58a22011-01-20 18:33:21 +1100948func (g *Generator) fileByName(filename string) *FileDescriptor {
949 for _, fd := range g.allFiles {
David Symonds8bb32ca2012-06-28 10:22:09 -0700950 if fd.GetName() == filename {
David Symonds31d58a22011-01-20 18:33:21 +1100951 return fd
952 }
953 }
954 return nil
955}
956
David Symonds9685cb02012-02-13 08:10:34 +1100957// weak returns whether the ith import of the current file is a weak import.
958func (g *Generator) weak(i int32) bool {
959 for _, j := range g.file.WeakDependency {
960 if j == i {
961 return true
962 }
963 }
964 return false
965}
966
David Symonds62539862012-08-04 10:06:55 +1000967// Generate the imports
Rob Pikeaf82b4e2010-04-30 15:19:25 -0700968func (g *Generator) generateImports() {
Rob Pikec9e7d972010-06-10 10:30:22 -0700969 // We almost always need a proto import. Rather than computing when we
970 // do, which is tricky when there's a plugin, just import it and
Rob Pikea17fdd92011-11-02 12:43:05 -0700971 // reference it later. The same argument applies to the math package,
David Symonds11db5982012-08-15 10:54:05 +1000972 // for handling bit patterns for floating-point numbers, and to the
973 // json package, for symbolic names of enum values for JSON marshaling.
David Symonds151cce02012-12-06 13:34:42 +1100974 g.P("import " + g.Pkg["proto"] + " " + strconv.Quote(g.ImportPrefix+"code.google.com/p/goprotobuf/proto"))
David Symonds11db5982012-08-15 10:54:05 +1000975 g.P("import " + g.Pkg["json"] + ` "encoding/json"`)
976 g.P("import " + g.Pkg["math"] + ` "math"`)
David Symonds9685cb02012-02-13 08:10:34 +1100977 for i, s := range g.file.Dependency {
David Symonds31d58a22011-01-20 18:33:21 +1100978 fd := g.fileByName(s)
979 // Do not import our own package.
980 if fd.PackageName() == g.packageName {
981 continue
982 }
983 filename := goFileName(s)
984 if substitution, ok := g.ImportMap[s]; ok {
985 filename = substitution
986 }
987 filename = g.ImportPrefix + filename
988 if strings.HasSuffix(filename, ".go") {
989 filename = filename[0 : len(filename)-3]
990 }
David Symonds9685cb02012-02-13 08:10:34 +1100991 // Skip weak imports.
992 if g.weak(int32(i)) {
David Symonds151cce02012-12-06 13:34:42 +1100993 g.P("// skipping weak import ", fd.PackageName(), " ", strconv.Quote(filename))
David Symonds9685cb02012-02-13 08:10:34 +1100994 continue
995 }
David Symonds31d58a22011-01-20 18:33:21 +1100996 if _, ok := g.usedPackages[fd.PackageName()]; ok {
David Symonds151cce02012-12-06 13:34:42 +1100997 g.P("import ", fd.PackageName(), " ", strconv.Quote(filename))
David Symonds31d58a22011-01-20 18:33:21 +1100998 } else {
David Symonds3fa055f2011-05-05 15:19:04 -0700999 // TODO: Re-enable this when we are more feature-complete.
1000 // For instance, some protos use foreign field extensions, which we don't support.
1001 // Until then, this is just annoying spam.
1002 //log.Printf("protoc-gen-go: discarding unused import from %v: %v", *g.file.Name, s)
David Symonds151cce02012-12-06 13:34:42 +11001003 g.P("// discarding unused import ", fd.PackageName(), " ", strconv.Quote(filename))
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001004 }
1005 }
1006 g.P()
1007 // TODO: may need to worry about uniqueness across plugins
1008 for _, p := range plugins {
Rob Pikec9e7d972010-06-10 10:30:22 -07001009 p.GenerateImports(g.file)
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001010 g.P()
1011 }
David Symonds62539862012-08-04 10:06:55 +10001012 g.P("// Reference proto, json, and math imports to suppress error if they are not otherwise used.")
David Symonds11db5982012-08-15 10:54:05 +10001013 g.P("var _ = ", g.Pkg["proto"], ".Marshal")
David Symonds62539862012-08-04 10:06:55 +10001014 g.P("var _ = &json.SyntaxError{}")
David Symondscea785b2011-01-07 11:02:30 +11001015 g.P("var _ = math.Inf")
Rob Pikec9e7d972010-06-10 10:30:22 -07001016 g.P()
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001017}
1018
David Symonds4decd802011-08-04 11:27:07 +10001019func (g *Generator) generateImported(id *ImportedDescriptor) {
David Symondsb2a00c82011-08-04 16:52:58 +10001020 // Don't generate public import symbols for files that we are generating
1021 // code for, since those symbols will already be in this package.
1022 // We can't simply avoid creating the ImportedDescriptor objects,
1023 // because g.genFiles isn't populated at that stage.
David Symonds4decd802011-08-04 11:27:07 +10001024 tn := id.TypeName()
1025 sn := tn[len(tn)-1]
David Symondsb2a00c82011-08-04 16:52:58 +10001026 df := g.FileOf(id.o.File())
1027 filename := *df.Name
1028 for _, fd := range g.genFiles {
1029 if *fd.Name == filename {
1030 g.P("// Ignoring public import of ", sn, " from ", filename)
1031 g.P()
1032 return
1033 }
1034 }
1035 g.P("// ", sn, " from public import ", filename)
1036 g.usedPackages[df.PackageName()] = true
David Symonds4decd802011-08-04 11:27:07 +10001037
David Symondsb2a00c82011-08-04 16:52:58 +10001038 for _, sym := range df.exported[id.o] {
1039 sym.GenerateAlias(g, df.PackageName())
1040 }
1041
1042 g.P()
David Symonds4decd802011-08-04 11:27:07 +10001043}
1044
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001045// Generate the enum definitions for this EnumDescriptor.
1046func (g *Generator) generateEnum(enum *EnumDescriptor) {
1047 // The full type name
1048 typeName := enum.TypeName()
1049 // The full type name, CamelCased.
1050 ccTypeName := CamelCaseSlice(typeName)
1051 ccPrefix := enum.prefix()
1052 g.P("type ", ccTypeName, " int32")
David Symondsb2a00c82011-08-04 16:52:58 +10001053 g.file.addExport(enum, enumSymbol(ccTypeName))
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001054 g.P("const (")
1055 g.In()
1056 for _, e := range enum.Value {
David Symonds31d58a22011-01-20 18:33:21 +11001057 name := ccPrefix + *e.Name
David Symondsdd9ca042011-08-29 16:07:16 +10001058 g.P(name, " ", ccTypeName, " = ", e.Number)
David Symondsb2a00c82011-08-04 16:52:58 +10001059 g.file.addExport(enum, constOrVarSymbol{name, "const"})
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001060 }
1061 g.Out()
1062 g.P(")")
David Symonds940b9612011-04-01 10:45:23 +11001063 g.P("var ", ccTypeName, "_name = map[int32]string{")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001064 g.In()
Rob Pikec9e7d972010-06-10 10:30:22 -07001065 generated := make(map[int32]bool) // avoid duplicate values
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001066 for _, e := range enum.Value {
1067 duplicate := ""
1068 if _, present := generated[*e.Number]; present {
1069 duplicate = "// Duplicate value: "
1070 }
David Symonds151cce02012-12-06 13:34:42 +11001071 g.P(duplicate, e.Number, ": ", strconv.Quote(*e.Name), ",")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001072 generated[*e.Number] = true
1073 }
1074 g.Out()
1075 g.P("}")
David Symonds940b9612011-04-01 10:45:23 +11001076 g.P("var ", ccTypeName, "_value = map[string]int32{")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001077 g.In()
1078 for _, e := range enum.Value {
David Symonds151cce02012-12-06 13:34:42 +11001079 g.P(strconv.Quote(*e.Name), ": ", e.Number, ",")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001080 }
1081 g.Out()
1082 g.P("}")
David Symonds940b9612011-04-01 10:45:23 +11001083
David Symondsefeca9a2012-05-08 10:36:04 +10001084 g.P("func (x ", ccTypeName, ") Enum() *", ccTypeName, " {")
1085 g.In()
1086 g.P("p := new(", ccTypeName, ")")
1087 g.P("*p = x")
1088 g.P("return p")
1089 g.Out()
1090 g.P("}")
1091
David Symonds940b9612011-04-01 10:45:23 +11001092 g.P("func (x ", ccTypeName, ") String() string {")
1093 g.In()
David Symonds11db5982012-08-15 10:54:05 +10001094 g.P("return ", g.Pkg["proto"], ".EnumName(", ccTypeName, "_name, int32(x))")
David Symonds940b9612011-04-01 10:45:23 +11001095 g.Out()
1096 g.P("}")
1097
David Symonds62539862012-08-04 10:06:55 +10001098 g.P("func (x ", ccTypeName, ") MarshalJSON() ([]byte, error) {")
1099 g.In()
1100 g.P("return json.Marshal(x.String())")
1101 g.Out()
1102 g.P("}")
1103
1104 g.P("func (x *", ccTypeName, ") UnmarshalJSON(data []byte) error {")
1105 g.In()
David Symonds11db5982012-08-15 10:54:05 +10001106 g.P("value, err := ", g.Pkg["proto"], ".UnmarshalJSONEnum(", ccTypeName, `_value, data, "`, ccTypeName, `")`)
David Symonds62539862012-08-04 10:06:55 +10001107 g.P("if err != nil {")
1108 g.In()
1109 g.P("return err")
1110 g.Out()
1111 g.P("}")
1112 g.P("*x = ", ccTypeName, "(value)")
1113 g.P("return nil")
1114 g.Out()
1115 g.P("}")
1116
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001117 g.P()
1118}
1119
David Symonds8935abf2011-07-04 15:53:16 +10001120// The tag is a string like "varint,2,opt,name=fieldname,def=7" that
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001121// identifies details of the field for the protocol buffer marshaling and unmarshaling
1122// code. The fields are:
1123// wire encoding
1124// protocol tag number
1125// opt,req,rep for optional, required, or repeated
David Symonds5b7775e2010-12-01 10:09:04 +11001126// packed whether the encoding is "packed" (optional; repeated primitives only)
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001127// name= the original declared name
1128// enum= the name of the enum type if it is an enum-typed field.
1129// def= string representation of the default value, if any.
1130// The default value must be in a representation that can be used at run-time
1131// to generate the default value. Thus bools become 0 and 1, for instance.
1132func (g *Generator) goTag(field *descriptor.FieldDescriptorProto, wiretype string) string {
1133 optrepreq := ""
1134 switch {
1135 case isOptional(field):
1136 optrepreq = "opt"
1137 case isRequired(field):
1138 optrepreq = "req"
1139 case isRepeated(field):
1140 optrepreq = "rep"
1141 }
David Symonds8bb32ca2012-06-28 10:22:09 -07001142 defaultValue := field.GetDefaultValue()
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001143 if defaultValue != "" {
1144 switch *field.Type {
1145 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1146 if defaultValue == "true" {
1147 defaultValue = "1"
1148 } else {
1149 defaultValue = "0"
1150 }
1151 case descriptor.FieldDescriptorProto_TYPE_STRING,
1152 descriptor.FieldDescriptorProto_TYPE_BYTES:
David Symondsb79d99b2011-08-29 16:38:49 +10001153 // Nothing to do. Quoting is done for the whole tag.
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001154 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1155 // For enums we need to provide the integer constant.
David Symonds8bb32ca2012-06-28 10:22:09 -07001156 obj := g.ObjectNamed(field.GetTypeName())
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001157 enum, ok := obj.(*EnumDescriptor)
1158 if !ok {
1159 g.Fail("enum type inconsistent for", CamelCaseSlice(obj.TypeName()))
1160 }
1161 defaultValue = enum.integerValueAsString(defaultValue)
1162 }
1163 defaultValue = ",def=" + defaultValue
1164 }
1165 enum := ""
1166 if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM {
David Symonds4decd802011-08-04 11:27:07 +10001167 // We avoid using obj.PackageName(), because we want to use the
1168 // original (proto-world) package name.
David Symonds8bb32ca2012-06-28 10:22:09 -07001169 obj := g.ObjectNamed(field.GetTypeName())
David Symonds4decd802011-08-04 11:27:07 +10001170 enum = ",enum="
David Symonds8bb32ca2012-06-28 10:22:09 -07001171 if pkg := obj.File().GetPackage(); pkg != "" {
David Symonds4decd802011-08-04 11:27:07 +10001172 enum += pkg + "."
1173 }
1174 enum += CamelCaseSlice(obj.TypeName())
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001175 }
David Symonds5b7775e2010-12-01 10:09:04 +11001176 packed := ""
David Symonds8bb32ca2012-06-28 10:22:09 -07001177 if field.Options != nil && field.Options.GetPacked() {
David Symonds5b7775e2010-12-01 10:09:04 +11001178 packed = ",packed"
1179 }
David Symonds8bb32ca2012-06-28 10:22:09 -07001180 fieldName := field.GetName()
David Symondse37856c2011-06-22 12:52:53 +10001181 name := fieldName
David Symonds9f402812011-04-28 18:08:44 +10001182 if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP {
1183 // We must use the type name for groups instead of
1184 // the field name to preserve capitalization.
1185 // type_name in FieldDescriptorProto is fully-qualified,
1186 // but we only want the local part.
1187 name = *field.TypeName
1188 if i := strings.LastIndex(name, "."); i >= 0 {
1189 name = name[i+1:]
1190 }
David Symondse37856c2011-06-22 12:52:53 +10001191 }
1192 if name == CamelCase(fieldName) {
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001193 name = ""
1194 } else {
1195 name = ",name=" + name
1196 }
David Symonds151cce02012-12-06 13:34:42 +11001197 return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s",
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001198 wiretype,
David Symonds8bb32ca2012-06-28 10:22:09 -07001199 field.GetNumber(),
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001200 optrepreq,
David Symonds5b7775e2010-12-01 10:09:04 +11001201 packed,
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001202 name,
1203 enum,
1204 defaultValue))
1205}
1206
1207func needsStar(typ descriptor.FieldDescriptorProto_Type) bool {
1208 switch typ {
1209 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1210 return false
1211 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1212 return false
1213 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1214 return false
1215 }
1216 return true
1217}
1218
1219// TypeName is the printed name appropriate for an item. If the object is in the current file,
1220// TypeName drops the package name and underscores the rest.
David Symonds7d5c8242011-03-14 12:03:50 -07001221// Otherwise the object is from another package; and the result is the underscored
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001222// package name followed by the item name.
1223// The result always has an initial capital.
1224func (g *Generator) TypeName(obj Object) string {
1225 return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName())
1226}
1227
1228// TypeNameWithPackage is like TypeName, but always includes the package
1229// name even if the object is in our own package.
1230func (g *Generator) TypeNameWithPackage(obj Object) string {
1231 return obj.PackageName() + CamelCaseSlice(obj.TypeName())
1232}
1233
1234// GoType returns a string representing the type name, and the wire type
1235func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) {
1236 // TODO: Options.
1237 switch *field.Type {
1238 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1239 typ, wire = "float64", "fixed64"
1240 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
1241 typ, wire = "float32", "fixed32"
1242 case descriptor.FieldDescriptorProto_TYPE_INT64:
1243 typ, wire = "int64", "varint"
1244 case descriptor.FieldDescriptorProto_TYPE_UINT64:
1245 typ, wire = "uint64", "varint"
1246 case descriptor.FieldDescriptorProto_TYPE_INT32:
1247 typ, wire = "int32", "varint"
1248 case descriptor.FieldDescriptorProto_TYPE_UINT32:
1249 typ, wire = "uint32", "varint"
1250 case descriptor.FieldDescriptorProto_TYPE_FIXED64:
1251 typ, wire = "uint64", "fixed64"
1252 case descriptor.FieldDescriptorProto_TYPE_FIXED32:
1253 typ, wire = "uint32", "fixed32"
1254 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1255 typ, wire = "bool", "varint"
1256 case descriptor.FieldDescriptorProto_TYPE_STRING:
1257 typ, wire = "string", "bytes"
1258 case descriptor.FieldDescriptorProto_TYPE_GROUP:
David Symonds8bb32ca2012-06-28 10:22:09 -07001259 desc := g.ObjectNamed(field.GetTypeName())
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001260 typ, wire = "*"+g.TypeName(desc), "group"
1261 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
David Symonds8bb32ca2012-06-28 10:22:09 -07001262 desc := g.ObjectNamed(field.GetTypeName())
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001263 typ, wire = "*"+g.TypeName(desc), "bytes"
1264 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1265 typ, wire = "[]byte", "bytes"
1266 case descriptor.FieldDescriptorProto_TYPE_ENUM:
David Symonds8bb32ca2012-06-28 10:22:09 -07001267 desc := g.ObjectNamed(field.GetTypeName())
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001268 typ, wire = g.TypeName(desc), "varint"
1269 case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
1270 typ, wire = "int32", "fixed32"
1271 case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
1272 typ, wire = "int64", "fixed64"
1273 case descriptor.FieldDescriptorProto_TYPE_SINT32:
1274 typ, wire = "int32", "zigzag32"
1275 case descriptor.FieldDescriptorProto_TYPE_SINT64:
1276 typ, wire = "int64", "zigzag64"
1277 default:
David Symonds8bb32ca2012-06-28 10:22:09 -07001278 g.Fail("unknown type for", field.GetName())
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001279 }
1280 if isRepeated(field) {
1281 typ = "[]" + typ
1282 } else if needsStar(*field.Type) {
1283 typ = "*" + typ
1284 }
1285 return
1286}
1287
David Symondsf90e3382010-05-05 10:53:44 +10001288func (g *Generator) RecordTypeUse(t string) {
1289 if obj, ok := g.typeNameToObject[t]; ok {
David Symonds4decd802011-08-04 11:27:07 +10001290 // Call ObjectNamed to get the true object to record the use.
1291 obj = g.ObjectNamed(t)
David Symondsf90e3382010-05-05 10:53:44 +10001292 g.usedPackages[obj.PackageName()] = true
1293 }
1294}
1295
David Symonds3ce53032012-02-13 10:55:03 +11001296// Method names that may be generated. Fields with these names get an
1297// underscore appended.
1298var methodNames = [...]string{
1299 "Reset",
1300 "String",
David Symonds9f60f432012-06-14 09:45:25 +10001301 "ProtoMessage",
David Symonds3ce53032012-02-13 10:55:03 +11001302 "Marshal",
1303 "Unmarshal",
1304 "ExtensionRangeArray",
1305 "ExtensionMap",
David Symonds4de8f722012-09-26 13:51:38 +10001306 "Descriptor",
David Symonds3ce53032012-02-13 10:55:03 +11001307}
1308
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001309// Generate the type and default constant definitions for this Descriptor.
1310func (g *Generator) generateMessage(message *Descriptor) {
1311 // The full type name
1312 typeName := message.TypeName()
1313 // The full type name, CamelCased.
1314 ccTypeName := CamelCaseSlice(typeName)
1315
David Symonds3ce53032012-02-13 10:55:03 +11001316 usedNames := make(map[string]bool)
1317 for _, n := range methodNames {
1318 usedNames[n] = true
1319 }
David Symonds8bb32ca2012-06-28 10:22:09 -07001320 fieldNames := make(map[*descriptor.FieldDescriptorProto]string)
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001321 g.P("type ", ccTypeName, " struct {")
1322 g.In()
David Symonds6eaeef12012-11-07 11:42:56 +11001323
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001324 for _, field := range message.Field {
1325 fieldname := CamelCase(*field.Name)
David Symonds3ce53032012-02-13 10:55:03 +11001326 for usedNames[fieldname] {
1327 fieldname += "_"
1328 }
1329 usedNames[fieldname] = true
David Symonds8bb32ca2012-06-28 10:22:09 -07001330 fieldNames[field] = fieldname
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001331 typename, wiretype := g.GoType(message, field)
David Symondsb2a00c82011-08-04 16:52:58 +10001332 jsonName := *field.Name
David Symonds6eaeef12012-11-07 11:42:56 +11001333 tag := fmt.Sprintf("protobuf:%s json:%q", g.goTag(field, wiretype), jsonName+",omitempty")
1334 g.P(fieldname, "\t", typename, "\t`", tag, "`")
David Symonds8bb32ca2012-06-28 10:22:09 -07001335 g.RecordTypeUse(field.GetTypeName())
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001336 }
1337 if len(message.ExtensionRange) > 0 {
David Symonds11db5982012-08-15 10:54:05 +10001338 g.P("XXX_extensions\t\tmap[int32]", g.Pkg["proto"], ".Extension `json:\"-\"`")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001339 }
David Symonds6eaeef12012-11-07 11:42:56 +11001340 if !message.group {
1341 g.P("XXX_unrecognized\t[]byte `json:\"-\"`")
1342 }
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001343 g.Out()
1344 g.P("}")
1345
David Symonds9f60f432012-06-14 09:45:25 +10001346 // Reset, String and ProtoMessage methods.
David Symondse37856c2011-06-22 12:52:53 +10001347 g.P("func (this *", ccTypeName, ") Reset() { *this = ", ccTypeName, "{} }")
David Symonds6eaeef12012-11-07 11:42:56 +11001348 if !message.group {
1349 g.P("func (this *", ccTypeName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(this) }")
1350 g.P("func (*", ccTypeName, ") ProtoMessage() {}")
1351 }
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001352
1353 // Extension support methods
David Symonds31d58a22011-01-20 18:33:21 +11001354 var hasExtensions, isMessageSet bool
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001355 if len(message.ExtensionRange) > 0 {
David Symonds31d58a22011-01-20 18:33:21 +11001356 hasExtensions = true
David Symonds4fee3b12010-11-11 10:00:13 +11001357 // message_set_wire_format only makes sense when extensions are defined.
David Symonds8bb32ca2012-06-28 10:22:09 -07001358 if opts := message.Options; opts != nil && opts.GetMessageSetWireFormat() {
David Symonds31d58a22011-01-20 18:33:21 +11001359 isMessageSet = true
David Symonds4fee3b12010-11-11 10:00:13 +11001360 g.P()
Rob Pikea17fdd92011-11-02 12:43:05 -07001361 g.P("func (this *", ccTypeName, ") Marshal() ([]byte, error) {")
David Symonds4fee3b12010-11-11 10:00:13 +11001362 g.In()
David Symonds11db5982012-08-15 10:54:05 +10001363 g.P("return ", g.Pkg["proto"], ".MarshalMessageSet(this.ExtensionMap())")
David Symonds4fee3b12010-11-11 10:00:13 +11001364 g.Out()
1365 g.P("}")
Rob Pikea17fdd92011-11-02 12:43:05 -07001366 g.P("func (this *", ccTypeName, ") Unmarshal(buf []byte) error {")
David Symonds4fee3b12010-11-11 10:00:13 +11001367 g.In()
David Symonds11db5982012-08-15 10:54:05 +10001368 g.P("return ", g.Pkg["proto"], ".UnmarshalMessageSet(buf, this.ExtensionMap())")
David Symonds4fee3b12010-11-11 10:00:13 +11001369 g.Out()
1370 g.P("}")
1371 g.P("// ensure ", ccTypeName, " satisfies proto.Marshaler and proto.Unmarshaler")
David Symonds11db5982012-08-15 10:54:05 +10001372 g.P("var _ ", g.Pkg["proto"], ".Marshaler = (*", ccTypeName, ")(nil)")
1373 g.P("var _ ", g.Pkg["proto"], ".Unmarshaler = (*", ccTypeName, ")(nil)")
David Symonds4fee3b12010-11-11 10:00:13 +11001374 }
1375
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001376 g.P()
David Symonds11db5982012-08-15 10:54:05 +10001377 g.P("var extRange_", ccTypeName, " = []", g.Pkg["proto"], ".ExtensionRange{")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001378 g.In()
1379 for _, r := range message.ExtensionRange {
Rob Pikec9e7d972010-06-10 10:30:22 -07001380 end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends
David Symonds1d72f7a2011-08-19 18:28:52 +10001381 g.P("{", r.Start, ", ", end, "},")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001382 }
1383 g.Out()
1384 g.P("}")
David Symonds11db5982012-08-15 10:54:05 +10001385 g.P("func (*", ccTypeName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001386 g.In()
1387 g.P("return extRange_", ccTypeName)
1388 g.Out()
1389 g.P("}")
David Symonds11db5982012-08-15 10:54:05 +10001390 g.P("func (this *", ccTypeName, ") ExtensionMap() map[int32]", g.Pkg["proto"], ".Extension {")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001391 g.In()
1392 g.P("if this.XXX_extensions == nil {")
1393 g.In()
David Symonds11db5982012-08-15 10:54:05 +10001394 g.P("this.XXX_extensions = make(map[int32]", g.Pkg["proto"], ".Extension)")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001395 g.Out()
1396 g.P("}")
1397 g.P("return this.XXX_extensions")
1398 g.Out()
1399 g.P("}")
1400 }
1401
1402 // Default constants
David Symonds8bb32ca2012-06-28 10:22:09 -07001403 defNames := make(map[*descriptor.FieldDescriptorProto]string)
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001404 for _, field := range message.Field {
David Symonds8bb32ca2012-06-28 10:22:09 -07001405 def := field.GetDefaultValue()
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001406 if def == "" {
1407 continue
1408 }
1409 fieldname := "Default_" + ccTypeName + "_" + CamelCase(*field.Name)
David Symonds8bb32ca2012-06-28 10:22:09 -07001410 defNames[field] = fieldname
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001411 typename, _ := g.GoType(message, field)
1412 if typename[0] == '*' {
1413 typename = typename[1:]
1414 }
1415 kind := "const "
1416 switch {
1417 case typename == "bool":
1418 case typename == "string":
David Symonds151cce02012-12-06 13:34:42 +11001419 def = strconv.Quote(def)
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001420 case typename == "[]byte":
David Symonds151cce02012-12-06 13:34:42 +11001421 def = "[]byte(" + strconv.Quote(def) + ")"
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001422 kind = "var "
David Symondscea785b2011-01-07 11:02:30 +11001423 case def == "inf", def == "-inf", def == "nan":
1424 // These names are known to, and defined by, the protocol language.
1425 switch def {
1426 case "inf":
1427 def = "math.Inf(1)"
1428 case "-inf":
1429 def = "math.Inf(-1)"
1430 case "nan":
1431 def = "math.NaN()"
1432 }
1433 if *field.Type == descriptor.FieldDescriptorProto_TYPE_FLOAT {
1434 def = "float32(" + def + ")"
1435 }
1436 kind = "var "
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001437 case *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM:
1438 // Must be an enum. Need to construct the prefixed name.
David Symonds8bb32ca2012-06-28 10:22:09 -07001439 obj := g.ObjectNamed(field.GetTypeName())
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001440 enum, ok := obj.(*EnumDescriptor)
1441 if !ok {
David Symondsd4661c52012-08-30 15:17:53 +10001442 log.Print("don't know how to generate constant for", fieldname)
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001443 continue
1444 }
Rob Pike87af39e2010-07-19 10:48:02 -07001445 def = g.DefaultPackageName(enum) + enum.prefix() + def
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001446 }
1447 g.P(kind, fieldname, " ", typename, " = ", def)
David Symondsb2a00c82011-08-04 16:52:58 +10001448 g.file.addExport(message, constOrVarSymbol{fieldname, kind})
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001449 }
1450 g.P()
1451
David Symonds8bb32ca2012-06-28 10:22:09 -07001452 // Field getters
David Symonds381349d2012-09-18 15:11:46 +10001453 var getters []getterSymbol
David Symonds8bb32ca2012-06-28 10:22:09 -07001454 for _, field := range message.Field {
1455 if isRepeated(field) {
1456 continue
1457 }
1458 fname := fieldNames[field]
1459 typename, _ := g.GoType(message, field)
David Symonds8bb32ca2012-06-28 10:22:09 -07001460 mname := "Get" + fname
1461 star := ""
1462 if needsStar(*field.Type) && typename[0] == '*' {
1463 typename = typename[1:]
1464 star = "*"
1465 }
David Symonds381349d2012-09-18 15:11:46 +10001466
1467 // Only export getter symbols for basic types,
David Symonds6eaeef12012-11-07 11:42:56 +11001468 // and for messages and enums in the same package.
1469 // Groups are not exported.
David Symonds381349d2012-09-18 15:11:46 +10001470 // Foreign types can't be hoisted through a public import because
1471 // the importer may not already be importing the defining .proto.
1472 // As an example, imagine we have an import tree like this:
1473 // A.proto -> B.proto -> C.proto
1474 // If A publicly imports B, we need to generate the getters from B in A's output,
1475 // but if one such getter returns something from C then we cannot do that
1476 // because A is not importing C already.
1477 var getter, genType bool
1478 switch *field.Type {
David Symonds6eaeef12012-11-07 11:42:56 +11001479 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1480 getter = false
1481 case descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_ENUM:
David Symonds381349d2012-09-18 15:11:46 +10001482 // Only export getter if its return type is in this package.
1483 getter = g.ObjectNamed(field.GetTypeName()).PackageName() == message.PackageName()
1484 genType = true
1485 default:
1486 getter = true
1487 }
1488 if getter {
1489 getters = append(getters, getterSymbol{
1490 name: mname,
1491 typ: typename,
1492 typeName: field.GetTypeName(),
1493 genType: genType,
1494 })
1495 }
1496
David Symonds8bb32ca2012-06-28 10:22:09 -07001497 g.P("func (this *", ccTypeName, ") "+mname+"() "+typename+" {")
1498 g.In()
1499 def, hasDef := defNames[field]
1500 typeDefaultIsNil := false // whether this field type's default value is a literal nil unless specified
1501 switch *field.Type {
1502 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1503 typeDefaultIsNil = !hasDef
1504 case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1505 typeDefaultIsNil = true
1506 }
1507 if typeDefaultIsNil {
1508 // A bytes field with no explicit default needs less generated code,
1509 // as does a message or group field.
1510 g.P("if this != nil {")
1511 g.In()
1512 g.P("return this." + fname)
1513 g.Out()
1514 g.P("}")
1515 g.P("return nil")
1516 g.Out()
1517 g.P("}")
1518 g.P()
1519 continue
1520 }
1521 g.P("if this != nil && this." + fname + " != nil {")
1522 g.In()
1523 g.P("return " + star + "this." + fname)
1524 g.Out()
1525 g.P("}")
1526 if hasDef {
1527 if *field.Type != descriptor.FieldDescriptorProto_TYPE_BYTES {
1528 g.P("return " + def)
1529 } else {
1530 // The default is a []byte var.
1531 // Make a copy when returning it to be safe.
1532 g.P("return append([]byte(nil), ", def, "...)")
1533 }
1534 } else {
1535 switch *field.Type {
1536 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1537 g.P("return false")
1538 case descriptor.FieldDescriptorProto_TYPE_STRING:
1539 g.P(`return ""`)
1540 default:
1541 g.P("return 0")
1542 }
1543 }
1544 g.Out()
1545 g.P("}")
1546 g.P()
1547 }
1548
David Symonds6eaeef12012-11-07 11:42:56 +11001549 if !message.group {
1550 g.file.addExport(message, &messageSymbol{ccTypeName, hasExtensions, isMessageSet, getters})
1551 }
David Symonds381349d2012-09-18 15:11:46 +10001552
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001553 for _, ext := range message.ext {
1554 g.generateExtension(ext)
1555 }
David Symonds525838c2012-07-20 15:42:49 +10001556
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001557}
1558
1559func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
David Symondse37856c2011-06-22 12:52:53 +10001560 ccTypeName := ext.DescName()
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001561
1562 extendedType := "*" + g.TypeName(g.ObjectNamed(*ext.Extendee))
1563 field := ext.FieldDescriptorProto
1564 fieldType, wireType := g.GoType(ext.parent, field)
1565 tag := g.goTag(field, wireType)
David Symondsf90e3382010-05-05 10:53:44 +10001566 g.RecordTypeUse(*ext.Extendee)
David Symonds9f402812011-04-28 18:08:44 +10001567 if n := ext.FieldDescriptorProto.TypeName; n != nil {
1568 // foreign extension type
1569 g.RecordTypeUse(*n)
1570 }
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001571
David Symonds20c73662012-01-20 07:32:21 +11001572 typeName := ext.TypeName()
1573
1574 // Special case for proto2 message sets: If this extension is extending
1575 // proto2_bridge.MessageSet, and its final name component is "message_set_extension",
1576 // then drop that last component.
1577 if extendedType == "*proto2_bridge.MessageSet" && typeName[len(typeName)-1] == "message_set_extension" {
1578 typeName = typeName[:len(typeName)-1]
1579 }
1580
David Symondsc057ad52012-02-11 15:43:42 +11001581 // For text formatting, the package must be exactly what the .proto file declares,
1582 // ignoring overrides such as the go_package option, and with no dot/underscore mapping.
1583 extName := strings.Join(typeName, ".")
1584 if g.file.Package != nil {
1585 extName = *g.file.Package + "." + extName
1586 }
1587
David Symonds11db5982012-08-15 10:54:05 +10001588 g.P("var ", ccTypeName, " = &", g.Pkg["proto"], ".ExtensionDesc{")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001589 g.In()
1590 g.P("ExtendedType: (", extendedType, ")(nil),")
1591 g.P("ExtensionType: (", fieldType, ")(nil),")
1592 g.P("Field: ", field.Number, ",")
David Symondsc057ad52012-02-11 15:43:42 +11001593 g.P(`Name: "`, extName, `",`)
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001594 g.P("Tag: ", tag, ",")
1595
1596 g.Out()
1597 g.P("}")
1598 g.P()
David Symonds31d58a22011-01-20 18:33:21 +11001599
David Symondsb2a00c82011-08-04 16:52:58 +10001600 g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var"})
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001601}
1602
1603func (g *Generator) generateInitFunction() {
1604 g.P("func init() {")
1605 g.In()
1606 for _, enum := range g.file.enum {
1607 g.generateEnumRegistration(enum)
1608 }
David Symondse37856c2011-06-22 12:52:53 +10001609 for _, d := range g.file.desc {
1610 for _, ext := range d.ext {
1611 g.generateExtensionRegistration(ext)
1612 }
1613 }
1614 for _, ext := range g.file.ext {
1615 g.generateExtensionRegistration(ext)
1616 }
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001617 g.Out()
1618 g.P("}")
1619}
1620
1621func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) {
David Symonds4decd802011-08-04 11:27:07 +10001622 // // We always print the full (proto-world) package name here.
David Symonds8bb32ca2012-06-28 10:22:09 -07001623 pkg := enum.File().GetPackage()
David Symonds4decd802011-08-04 11:27:07 +10001624 if pkg != "" {
1625 pkg += "."
1626 }
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001627 // The full type name
1628 typeName := enum.TypeName()
1629 // The full type name, CamelCased.
1630 ccTypeName := CamelCaseSlice(typeName)
David Symonds151cce02012-12-06 13:34:42 +11001631 g.P(g.Pkg["proto"]+".RegisterEnum(", strconv.Quote(pkg+ccTypeName), ", ", ccTypeName+"_name, ", ccTypeName+"_value)")
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001632}
1633
David Symondse37856c2011-06-22 12:52:53 +10001634func (g *Generator) generateExtensionRegistration(ext *ExtensionDescriptor) {
David Symonds11db5982012-08-15 10:54:05 +10001635 g.P(g.Pkg["proto"]+".RegisterExtension(", ext.DescName(), ")")
David Symondse37856c2011-06-22 12:52:53 +10001636}
1637
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001638// And now lots of helper functions.
1639
Rob Pike2c7bafc2010-06-10 16:07:14 -07001640// Is c an ASCII lower-case letter?
1641func isASCIILower(c byte) bool {
1642 return 'a' <= c && c <= 'z'
1643}
1644
1645// Is c an ASCII digit?
1646func isASCIIDigit(c byte) bool {
1647 return '0' <= c && c <= '9'
1648}
1649
1650// CamelCase returns the CamelCased name.
1651// If there is an interior underscore followed by a lower case letter,
1652// drop the underscore and convert the letter to upper case.
1653// There is a remote possibility of this rewrite causing a name collision,
1654// but it's so remote we're prepared to pretend it's nonexistent - since the
1655// C++ generator lowercases names, it's extremely unlikely to have two fields
1656// with different capitalizations.
1657// In short, _my_field_name_2 becomes XMyFieldName2.
1658func CamelCase(s string) string {
1659 if s == "" {
1660 return ""
1661 }
1662 t := make([]byte, 0, 32)
Rob Pike2c7bafc2010-06-10 16:07:14 -07001663 i := 0
1664 if s[0] == '_' {
1665 // Need a capital letter; drop the '_'.
Rob Pike99fa2b62010-12-02 10:39:42 -08001666 t = append(t, 'X')
Rob Pike2c7bafc2010-06-10 16:07:14 -07001667 i++
1668 }
1669 // Invariant: if the next letter is lower case, it must be converted
1670 // to upper case.
1671 // That is, we process a word at a time, where words are marked by _ or
1672 // upper case letter. Digits are treated as words.
1673 for ; i < len(s); i++ {
1674 c := s[i]
Rob Pike2c7bafc2010-06-10 16:07:14 -07001675 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
1676 continue // Skip the underscore in s.
1677 }
1678 if isASCIIDigit(c) {
Rob Pike99fa2b62010-12-02 10:39:42 -08001679 t = append(t, c)
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001680 continue
1681 }
Rob Pike2c7bafc2010-06-10 16:07:14 -07001682 // Assume we have a letter now - if not, it's a bogus identifier.
1683 // The next word is a sequence of characters that must start upper case.
1684 if isASCIILower(c) {
Rob Pike99fa2b62010-12-02 10:39:42 -08001685 c ^= ' ' // Make it a capital letter.
Rob Pike2c7bafc2010-06-10 16:07:14 -07001686 }
Rob Pike99fa2b62010-12-02 10:39:42 -08001687 t = append(t, c) // Guaranteed not lower case.
Rob Pike2c7bafc2010-06-10 16:07:14 -07001688 // Accept lower case sequence that follows.
1689 for i+1 < len(s) && isASCIILower(s[i+1]) {
1690 i++
Rob Pike99fa2b62010-12-02 10:39:42 -08001691 t = append(t, s[i])
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001692 }
1693 }
Rob Pike2c7bafc2010-06-10 16:07:14 -07001694 return string(t)
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001695}
1696
1697// CamelCaseSlice is like CamelCase, but the argument is a slice of strings to
1698// be joined with "_".
1699func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) }
1700
1701// dottedSlice turns a sliced name into a dotted name.
1702func dottedSlice(elem []string) string { return strings.Join(elem, ".") }
1703
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001704// Given a .proto file name, return the output name for the generated Go program.
1705func goFileName(name string) string {
Rob Pike87af39e2010-07-19 10:48:02 -07001706 ext := path.Ext(name)
1707 if ext == ".proto" || ext == ".protodevel" {
1708 name = name[0 : len(name)-len(ext)]
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001709 }
1710 return name + ".pb.go"
1711}
1712
1713// Is this field optional?
1714func isOptional(field *descriptor.FieldDescriptorProto) bool {
1715 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
1716}
1717
1718// Is this field required?
1719func isRequired(field *descriptor.FieldDescriptorProto) bool {
1720 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED
1721}
1722
1723// Is this field repeated?
1724func isRepeated(field *descriptor.FieldDescriptorProto) bool {
1725 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
1726}
1727
David Symonds151cce02012-12-06 13:34:42 +11001728// badToUnderscore is the mapping function used to generate Go names from package names,
David Symonds162d0032012-06-28 09:44:46 -07001729// which can be dotted in the input .proto file. It replaces non-identifier characters such as
1730// dot or dash with underscore.
David Symonds151cce02012-12-06 13:34:42 +11001731func badToUnderscore(r rune) rune {
David Symonds162d0032012-06-28 09:44:46 -07001732 if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
1733 return r
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001734 }
David Symonds162d0032012-06-28 09:44:46 -07001735 return '_'
Rob Pikeaf82b4e2010-04-30 15:19:25 -07001736}
Rob Pikec9e7d972010-06-10 10:30:22 -07001737
David Symonds151cce02012-12-06 13:34:42 +11001738// baseName returns the last path element of the name, with the last dotted suffix removed.
1739func baseName(name string) string {
Rob Pikec9e7d972010-06-10 10:30:22 -07001740 // First, find the last element
1741 if i := strings.LastIndex(name, "/"); i >= 0 {
1742 name = name[i+1:]
1743 }
1744 // Now drop the suffix
1745 if i := strings.LastIndex(name, "."); i >= 0 {
1746 name = name[0:i]
1747 }
1748 return name
1749}