cmd/protoc-gen-go: generate enums

This produces exactly the same output (to the best of my ability to
determine) as github.com/golang/protobuf.

Change-Id: Ib60e7a836efb1eb0e5167b30458049ec239e7903
Reviewed-on: https://go-review.googlesource.com/134695
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
This commit is contained in:
Damien Neil 2018-09-07 12:45:37 -07:00
parent cab8dfee90
commit 46abb57549
6 changed files with 605 additions and 18 deletions

View File

@ -18,8 +18,11 @@ import (
"github.com/golang/protobuf/proto"
descpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
"google.golang.org/proto/protogen"
"google.golang.org/proto/reflect/protoreflect"
)
const protoPackage = "github.com/golang/protobuf/proto"
func main() {
protogen.Run(func(gen *protogen.Plugin) error {
for _, f := range gen.Files {
@ -34,7 +37,9 @@ func main() {
type File struct {
*protogen.File
locationMap map[string][]*descpb.SourceCodeInfo_Location
locationMap map[string][]*descpb.SourceCodeInfo_Location
descriptorVar string // var containing the gzipped FileDescriptorProto
init []string
}
func genFile(gen *protogen.Plugin, file *protogen.File) {
@ -47,6 +52,12 @@ func genFile(gen *protogen.Plugin, file *protogen.File) {
f.locationMap[key] = append(f.locationMap[key], loc)
}
// Determine the name of the var holding the file descriptor:
//
// fileDescriptor_<hash of filename>
filenameHash := sha256.Sum256([]byte(f.Desc.Path()))
f.descriptorVar = fmt.Sprintf("fileDescriptor_%s", hex.EncodeToString(filenameHash[:8]))
g := gen.NewGeneratedFile(f.GeneratedFilenamePrefix+".pb.go", f.GoImportPath)
g.P("// Code generated by protoc-gen-go. DO NOT EDIT.")
g.P("// source: ", f.Desc.Path())
@ -57,20 +68,26 @@ func genFile(gen *protogen.Plugin, file *protogen.File) {
g.P("package ", f.GoPackageName)
g.P()
for _, enum := range f.Enums {
genEnum(gen, g, f, enum)
}
for _, message := range f.Messages {
genMessage(gen, g, f, message)
}
if len(f.init) != 0 {
g.P("func init() {")
for _, s := range f.init {
g.P(s)
}
g.P("}")
g.P()
}
genFileDescriptor(gen, g, f)
}
func genFileDescriptor(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File) {
// Determine the name of the var holding the file descriptor:
//
// fileDescriptor_<hash of filename>
filenameHash := sha256.Sum256([]byte(f.Desc.Path()))
varName := fmt.Sprintf("fileDescriptor_%s", hex.EncodeToString(filenameHash[:8]))
// Trim the source_code_info from the descriptor.
// Marshal and gzip it.
descProto := proto.Clone(f.Proto).(*descpb.FileDescriptorProto)
@ -86,9 +103,9 @@ func genFileDescriptor(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File)
w.Close()
b = buf.Bytes()
g.P("func init() { proto.RegisterFile(", strconv.Quote(f.Desc.Path()), ", ", varName, ") }")
g.P("func init() { proto.RegisterFile(", strconv.Quote(f.Desc.Path()), ", ", f.descriptorVar, ") }")
g.P()
g.P("var ", varName, " = []byte{")
g.P("var ", f.descriptorVar, " = []byte{")
g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto")
for len(b) > 0 {
n := 16
@ -108,7 +125,92 @@ func genFileDescriptor(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File)
g.P()
}
func genEnum(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, enum *protogen.Enum) {
genComment(g, f, enum.Path)
// TODO: deprecation
g.P("type ", enum.GoIdent, " int32")
g.P("const (")
for _, value := range enum.Values {
genComment(g, f, value.Path)
// TODO: deprecation
g.P(value.GoIdent, " ", enum.GoIdent, " = ", value.Desc.Number())
}
g.P(")")
g.P()
nameMap := enum.GoIdent.GoName + "_name"
g.P("var ", nameMap, " = map[int32]string{")
generated := make(map[protoreflect.EnumNumber]bool)
for _, value := range enum.Values {
duplicate := ""
if _, present := generated[value.Desc.Number()]; present {
duplicate = "// Duplicate value: "
}
g.P(duplicate, value.Desc.Number(), ": ", strconv.Quote(string(value.Desc.Name())), ",")
generated[value.Desc.Number()] = true
}
g.P("}")
g.P()
valueMap := enum.GoIdent.GoName + "_value"
g.P("var ", valueMap, " = map[string]int32{")
for _, value := range enum.Values {
g.P(strconv.Quote(string(value.Desc.Name())), ": ", value.Desc.Number(), ",")
}
g.P("}")
g.P()
if enum.Desc.Syntax() != protoreflect.Proto3 {
g.P("func (x ", enum.GoIdent, ") Enum() *", enum.GoIdent, " {")
g.P("p := new(", enum.GoIdent, ")")
g.P("*p = x")
g.P("return p")
g.P("}")
g.P()
}
g.P("func (x ", enum.GoIdent, ") String() string {")
g.P("return ", protogen.GoIdent{GoImportPath: protoPackage, GoName: "EnumName"}, "(", enum.GoIdent, "_name, int32(x))")
g.P("}")
g.P()
if enum.Desc.Syntax() != protoreflect.Proto3 {
g.P("func (x *", enum.GoIdent, ") UnmarshalJSON(data []byte) error {")
g.P("value, err := ", protogen.GoIdent{GoImportPath: protoPackage, GoName: "UnmarshalJSONEnum"}, "(", enum.GoIdent, `_value, data, "`, enum.GoIdent, `")`)
g.P("if err != nil {")
g.P("return err")
g.P("}")
g.P("*x = ", enum.GoIdent, "(value)")
g.P("return nil")
g.P("}")
g.P()
}
var indexes []string
for i := 1; i < len(enum.Path); i += 2 {
indexes = append(indexes, strconv.Itoa(int(enum.Path[i])))
}
g.P("func (", enum.GoIdent, ") EnumDescriptor() ([]byte, []int) {")
g.P("return ", f.descriptorVar, ", []int{", strings.Join(indexes, ","), "}")
g.P("}")
g.P()
genWellKnownType(g, enum.GoIdent, enum.Desc)
// The name registered is, confusingly, <proto_package>.<go_ident>.
// This probably should have been the full name of the proto enum
// type instead, but changing it at this point would require thought.
regName := string(f.Desc.Package()) + "." + enum.GoIdent.GoName
f.init = append(f.init, fmt.Sprintf("%s(%q, %s, %s)",
g.QualifiedGoIdent(protogen.GoIdent{
GoImportPath: protoPackage,
GoName: "RegisterEnum",
}),
regName, nameMap, valueMap,
))
}
func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, message *protogen.Message) {
for _, enum := range message.Enums {
genEnum(gen, g, f, enum)
}
genComment(g, f, message.Path)
g.P("type ", message.GoIdent, " struct {")
g.P("}")
@ -142,3 +244,15 @@ func pathKey(path []int32) string {
}
return string(buf)
}
func genWellKnownType(g *protogen.GeneratedFile, ident protogen.GoIdent, desc protoreflect.Descriptor) {
if wellKnownTypes[desc.FullName()] {
g.P("func (", ident, `) XXX_WellKnownType() string { return "`, desc.Name(), `" }`)
g.P()
}
}
// Names of messages and enums for which we will generate XXX_WellKnownType methods.
var wellKnownTypes = map[protoreflect.FullName]bool{
"google.protobuf.NullValue": true,
}

View File

@ -0,0 +1,278 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: proto2/enum.proto
package proto2
import proto "github.com/golang/protobuf/proto"
// EnumType1 comment.
type EnumType1 int32
const (
// EnumType1_ONE comment.
EnumType1_ONE EnumType1 = 1
// EnumType1_TWO comment.
EnumType1_TWO EnumType1 = 2
)
var EnumType1_name = map[int32]string{
1: "ONE",
2: "TWO",
}
var EnumType1_value = map[string]int32{
"ONE": 1,
"TWO": 2,
}
func (x EnumType1) Enum() *EnumType1 {
p := new(EnumType1)
*p = x
return p
}
func (x EnumType1) String() string {
return proto.EnumName(EnumType1_name, int32(x))
}
func (x *EnumType1) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(EnumType1_value, data, "EnumType1")
if err != nil {
return err
}
*x = EnumType1(value)
return nil
}
func (EnumType1) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_de9f68860d540858, []int{0}
}
type EnumType2 int32
const (
EnumType2_duplicate1 EnumType2 = 1
EnumType2_duplicate2 EnumType2 = 1
)
var EnumType2_name = map[int32]string{
1: "duplicate1",
// Duplicate value: 1: "duplicate2",
}
var EnumType2_value = map[string]int32{
"duplicate1": 1,
"duplicate2": 1,
}
func (x EnumType2) Enum() *EnumType2 {
p := new(EnumType2)
*p = x
return p
}
func (x EnumType2) String() string {
return proto.EnumName(EnumType2_name, int32(x))
}
func (x *EnumType2) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(EnumType2_value, data, "EnumType2")
if err != nil {
return err
}
*x = EnumType2(value)
return nil
}
func (EnumType2) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_de9f68860d540858, []int{1}
}
// NestedEnumType1A comment.
type EnumContainerMessage1_NestedEnumType1A int32
const (
// NestedEnumType1A_VALUE comment.
EnumContainerMessage1_NESTED_1A_VALUE EnumContainerMessage1_NestedEnumType1A = 0
)
var EnumContainerMessage1_NestedEnumType1A_name = map[int32]string{
0: "NESTED_1A_VALUE",
}
var EnumContainerMessage1_NestedEnumType1A_value = map[string]int32{
"NESTED_1A_VALUE": 0,
}
func (x EnumContainerMessage1_NestedEnumType1A) Enum() *EnumContainerMessage1_NestedEnumType1A {
p := new(EnumContainerMessage1_NestedEnumType1A)
*p = x
return p
}
func (x EnumContainerMessage1_NestedEnumType1A) String() string {
return proto.EnumName(EnumContainerMessage1_NestedEnumType1A_name, int32(x))
}
func (x *EnumContainerMessage1_NestedEnumType1A) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(EnumContainerMessage1_NestedEnumType1A_value, data, "EnumContainerMessage1_NestedEnumType1A")
if err != nil {
return err
}
*x = EnumContainerMessage1_NestedEnumType1A(value)
return nil
}
func (EnumContainerMessage1_NestedEnumType1A) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_de9f68860d540858, []int{0, 0}
}
type EnumContainerMessage1_NestedEnumType1B int32
const (
EnumContainerMessage1_NESTED_1B_VALUE EnumContainerMessage1_NestedEnumType1B = 0
)
var EnumContainerMessage1_NestedEnumType1B_name = map[int32]string{
0: "NESTED_1B_VALUE",
}
var EnumContainerMessage1_NestedEnumType1B_value = map[string]int32{
"NESTED_1B_VALUE": 0,
}
func (x EnumContainerMessage1_NestedEnumType1B) Enum() *EnumContainerMessage1_NestedEnumType1B {
p := new(EnumContainerMessage1_NestedEnumType1B)
*p = x
return p
}
func (x EnumContainerMessage1_NestedEnumType1B) String() string {
return proto.EnumName(EnumContainerMessage1_NestedEnumType1B_name, int32(x))
}
func (x *EnumContainerMessage1_NestedEnumType1B) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(EnumContainerMessage1_NestedEnumType1B_value, data, "EnumContainerMessage1_NestedEnumType1B")
if err != nil {
return err
}
*x = EnumContainerMessage1_NestedEnumType1B(value)
return nil
}
func (EnumContainerMessage1_NestedEnumType1B) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_de9f68860d540858, []int{0, 1}
}
type EnumContainerMessage1 struct {
}
// NestedEnumType2A comment.
type EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A int32
const (
// NestedEnumType2A_VALUE comment.
EnumContainerMessage1_EnumContainerMessage2_NESTED_2A_VALUE EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A = 0
)
var EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A_name = map[int32]string{
0: "NESTED_2A_VALUE",
}
var EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A_value = map[string]int32{
"NESTED_2A_VALUE": 0,
}
func (x EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A) Enum() *EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A {
p := new(EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A)
*p = x
return p
}
func (x EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A) String() string {
return proto.EnumName(EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A_name, int32(x))
}
func (x *EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A_value, data, "EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A")
if err != nil {
return err
}
*x = EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A(value)
return nil
}
func (EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_de9f68860d540858, []int{0, 0, 0}
}
type EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B int32
const (
EnumContainerMessage1_EnumContainerMessage2_NESTED_2B_VALUE EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B = 0
)
var EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B_name = map[int32]string{
0: "NESTED_2B_VALUE",
}
var EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B_value = map[string]int32{
"NESTED_2B_VALUE": 0,
}
func (x EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B) Enum() *EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B {
p := new(EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B)
*p = x
return p
}
func (x EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B) String() string {
return proto.EnumName(EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B_name, int32(x))
}
func (x *EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B_value, data, "EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B")
if err != nil {
return err
}
*x = EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B(value)
return nil
}
func (EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_de9f68860d540858, []int{0, 0, 1}
}
type EnumContainerMessage1_EnumContainerMessage2 struct {
}
func init() {
proto.RegisterEnum("goproto.protoc.proto2.EnumType1", EnumType1_name, EnumType1_value)
proto.RegisterEnum("goproto.protoc.proto2.EnumType2", EnumType2_name, EnumType2_value)
proto.RegisterEnum("goproto.protoc.proto2.EnumContainerMessage1_NestedEnumType1A", EnumContainerMessage1_NestedEnumType1A_name, EnumContainerMessage1_NestedEnumType1A_value)
proto.RegisterEnum("goproto.protoc.proto2.EnumContainerMessage1_NestedEnumType1B", EnumContainerMessage1_NestedEnumType1B_name, EnumContainerMessage1_NestedEnumType1B_value)
proto.RegisterEnum("goproto.protoc.proto2.EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A", EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A_name, EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2A_value)
proto.RegisterEnum("goproto.protoc.proto2.EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B", EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B_name, EnumContainerMessage1_EnumContainerMessage2_NestedEnumType2B_value)
}
func init() { proto.RegisterFile("proto2/enum.proto", fileDescriptor_de9f68860d540858) }
var fileDescriptor_de9f68860d540858 = []byte{
// 242 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xb1, 0x4b, 0xc4, 0x30,
0x14, 0xc6, 0xcd, 0x39, 0x88, 0x19, 0x34, 0x56, 0x6e, 0x39, 0x70, 0xb9, 0x45, 0x38, 0xb8, 0x86,
0x64, 0x13, 0xa7, 0x56, 0xb3, 0x69, 0x6f, 0xb0, 0x2a, 0xb8, 0x1c, 0xa1, 0x7d, 0x3c, 0x0a, 0x6d,
0x5e, 0x69, 0xd3, 0xc1, 0xff, 0xd3, 0x3f, 0x48, 0xae, 0x81, 0xb3, 0x42, 0x75, 0xca, 0xf7, 0xe5,
0xfb, 0xf1, 0x1b, 0x1e, 0xbf, 0x6a, 0x3b, 0xf2, 0xa4, 0x25, 0xb8, 0xa1, 0x89, 0xc7, 0x1c, 0x2d,
0x91, 0xc6, 0x10, 0x6a, 0x11, 0x1e, 0xbd, 0xfe, 0x62, 0x7c, 0x69, 0xdc, 0xd0, 0x3c, 0x90, 0xf3,
0xb6, 0x72, 0xd0, 0x3d, 0x43, 0xdf, 0x5b, 0x04, 0xb5, 0xaa, 0xe6, 0x07, 0xbd, 0xbe, 0xe5, 0x22,
0x83, 0xde, 0x43, 0x79, 0x98, 0xf3, 0xcf, 0x16, 0x74, 0x12, 0x5d, 0xf3, 0xcb, 0xcc, 0xbc, 0xe4,
0xe6, 0x71, 0xaf, 0x93, 0xfd, 0x5b, 0xf2, 0xf4, 0x6a, 0xc4, 0xc9, 0x0c, 0x98, 0x4e, 0xc1, 0xf4,
0x6f, 0x50, 0x4d, 0x8d, 0xea, 0x1f, 0xa3, 0x9a, 0x1a, 0xd5, 0xd1, 0xb8, 0xb9, 0xe1, 0xe7, 0x47,
0x24, 0x3a, 0xe3, 0xa7, 0xbb, 0xcc, 0x08, 0x76, 0x08, 0xf9, 0xfb, 0x4e, 0x2c, 0x36, 0xf2, 0x67,
0xd6, 0xd1, 0x05, 0xe7, 0xe5, 0xd0, 0xd6, 0x55, 0x61, 0x3d, 0x28, 0xc1, 0x7e, 0x75, 0x2d, 0xd8,
0x6a, 0x21, 0x58, 0x7a, 0xff, 0x71, 0x87, 0x44, 0x58, 0x43, 0x8c, 0x54, 0x5b, 0x87, 0x31, 0x75,
0x28, 0xc7, 0x13, 0xca, 0xa2, 0x29, 0x43, 0x2a, 0xb6, 0x08, 0x6e, 0x8b, 0x24, 0x3d, 0xf4, 0xbe,
0xb4, 0xde, 0x86, 0x6f, 0xfd, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xf6, 0x53, 0xf7, 0xde, 0x8e, 0x01,
0x00, 0x00,
}

View File

@ -0,0 +1,47 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
syntax = "proto2";
package goproto.protoc.proto2;
option go_package = "google.golang.org/proto/cmd/protoc-gen-go/testdata/proto2";
// EnumType1 comment.
enum EnumType1 {
// EnumType1_ONE comment.
ONE = 1;
// EnumType1_TWO comment.
TWO = 2;
}
enum EnumType2 {
option allow_alias = true;
duplicate1 = 1;
duplicate2 = 1;
}
message EnumContainerMessage1 {
// NestedEnumType1A comment.
enum NestedEnumType1A {
// NestedEnumType1A_VALUE comment.
NESTED_1A_VALUE = 0;
}
enum NestedEnumType1B {
NESTED_1B_VALUE = 0;
}
message EnumContainerMessage2 {
// NestedEnumType2A comment.
enum NestedEnumType2A {
// NestedEnumType2A_VALUE comment.
NESTED_2A_VALUE = 0;
}
enum NestedEnumType2B {
NESTED_2B_VALUE = 0;
}
}
}

View File

@ -0,0 +1,53 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: proto3/enum.proto
package proto3
import proto "github.com/golang/protobuf/proto"
type Enum int32
const (
Enum_ZERO Enum = 0
Enum_ONE Enum = 1
Enum_TWO Enum = 2
)
var Enum_name = map[int32]string{
0: "ZERO",
1: "ONE",
2: "TWO",
}
var Enum_value = map[string]int32{
"ZERO": 0,
"ONE": 1,
"TWO": 2,
}
func (x Enum) String() string {
return proto.EnumName(Enum_name, int32(x))
}
func (Enum) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_b4b9b1e8d161a9a6, []int{0}
}
func init() {
proto.RegisterEnum("goproto.protoc.proto3.Enum", Enum_name, Enum_value)
}
func init() { proto.RegisterFile("proto3/enum.proto", fileDescriptor_b4b9b1e8d161a9a6) }
var fileDescriptor_b4b9b1e8d161a9a6 = []byte{
// 138 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0x28, 0xca, 0x2f,
0xc9, 0x37, 0xd6, 0x4f, 0xcd, 0x2b, 0xcd, 0xd5, 0x03, 0xb3, 0x85, 0x44, 0xd3, 0xf3, 0xc1, 0x0c,
0x08, 0x37, 0x19, 0x42, 0x19, 0x6b, 0x29, 0x71, 0xb1, 0xb8, 0xe6, 0x95, 0xe6, 0x0a, 0x71, 0x70,
0xb1, 0x44, 0xb9, 0x06, 0xf9, 0x0b, 0x30, 0x08, 0xb1, 0x73, 0x31, 0xfb, 0xfb, 0xb9, 0x0a, 0x30,
0x82, 0x18, 0x21, 0xe1, 0xfe, 0x02, 0x4c, 0x4e, 0xd6, 0x51, 0x96, 0xe9, 0xf9, 0xf9, 0xe9, 0x39,
0xa9, 0x7a, 0xe9, 0xf9, 0x39, 0x89, 0x79, 0xe9, 0x7a, 0xf9, 0x45, 0xe9, 0xfa, 0x60, 0xfd, 0xfa,
0xc9, 0xb9, 0x29, 0x10, 0x56, 0xb2, 0x6e, 0x7a, 0x6a, 0x9e, 0x6e, 0x7a, 0xbe, 0x7e, 0x49, 0x6a,
0x71, 0x49, 0x4a, 0x62, 0x49, 0x22, 0x44, 0xd8, 0x38, 0x89, 0x0d, 0x42, 0x03, 0x02, 0x00, 0x00,
0xff, 0xff, 0x02, 0x01, 0x6a, 0x95, 0x93, 0x00, 0x00, 0x00,
}

View File

@ -0,0 +1,15 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
syntax = "proto3";
package goproto.protoc.proto3;
option go_package = "google.golang.org/proto/cmd/protoc-gen-go/testdata/proto3";
enum Enum {
ZERO = 0;
ONE = 1;
TWO = 2;
}

View File

@ -305,6 +305,7 @@ type File struct {
GoPackageName GoPackageName // name of this file's Go package
GoImportPath GoImportPath // import path of this file's Go package
Messages []*Message // top-level message declarations
Enums []*Enum // top-level enum declarations
Generate bool // true if we should generate code for this file
// GeneratedFilenamePrefix is used to construct filenames for generated
@ -351,6 +352,9 @@ func newFile(gen *Plugin, p *descpb.FileDescriptorProto, packageName GoPackageNa
for i, mdescs := 0, desc.Messages(); i < mdescs.Len(); i++ {
f.Messages = append(f.Messages, newMessage(gen, f, nil, mdescs.Get(i)))
}
for i, edescs := 0, desc.Enums(); i < edescs.Len(); i++ {
f.Enums = append(f.Enums, newEnum(gen, f, nil, edescs.Get(i)))
}
return f, nil
}
@ -380,6 +384,7 @@ type Message struct {
GoIdent GoIdent // name of the generated Go type
Messages []*Message // nested message declarations
Enums []*Enum // nested enum declarations
Path []int32 // location path of this message
}
@ -390,15 +395,73 @@ func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.Message
} else {
path = []int32{fileMessageField, int32(desc.Index())}
}
m := &Message{
message := &Message{
Desc: desc,
GoIdent: newGoIdent(f, desc),
Path: path,
}
for i, mdescs := 0, desc.Messages(); i < mdescs.Len(); i++ {
m.Messages = append(m.Messages, newMessage(gen, f, m, mdescs.Get(i)))
message.Messages = append(message.Messages, newMessage(gen, f, message, mdescs.Get(i)))
}
for i, edescs := 0, desc.Enums(); i < edescs.Len(); i++ {
message.Enums = append(message.Enums, newEnum(gen, f, message, edescs.Get(i)))
}
return message
}
// An Enum describes an enum.
type Enum struct {
Desc protoreflect.EnumDescriptor
GoIdent GoIdent // name of the generated Go type
Values []*EnumValue // enum values
Path []int32 // location path of this enum
}
func newEnum(gen *Plugin, f *File, parent *Message, desc protoreflect.EnumDescriptor) *Enum {
var path []int32
if parent != nil {
path = pathAppend(parent.Path, messageEnumField, int32(desc.Index()))
} else {
path = []int32{fileEnumField, int32(desc.Index())}
}
enum := &Enum{
Desc: desc,
GoIdent: newGoIdent(f, desc),
Path: path,
}
for i, evdescs := 0, enum.Desc.Values(); i < evdescs.Len(); i++ {
enum.Values = append(enum.Values, newEnumValue(gen, f, parent, enum, evdescs.Get(i)))
}
return enum
}
// An EnumValue describes an enum value.
type EnumValue struct {
Desc protoreflect.EnumValueDescriptor
GoIdent GoIdent // name of the generated Go type
Path []int32 // location path of this enum value
}
func newEnumValue(gen *Plugin, f *File, message *Message, enum *Enum, desc protoreflect.EnumValueDescriptor) *EnumValue {
// A top-level enum value's name is: EnumName_ValueName
// An enum value contained in a message is: MessageName_ValueName
//
// Enum value names are not camelcased.
parentIdent := enum.GoIdent
if message != nil {
parentIdent = message.GoIdent
}
name := parentIdent.GoName + "_" + string(desc.Name())
return &EnumValue{
Desc: desc,
GoIdent: GoIdent{
GoName: name,
GoImportPath: f.GoImportPath,
},
Path: pathAppend(enum.Path, enumValueField, int32(desc.Index())),
}
return m
}
// A GeneratedFile is a generated file.
@ -432,11 +495,7 @@ func (g *GeneratedFile) P(v ...interface{}) {
for _, x := range v {
switch x := x.(type) {
case GoIdent:
if x.GoImportPath != g.goImportPath {
fmt.Fprint(&g.buf, g.goPackageName(x.GoImportPath))
fmt.Fprint(&g.buf, ".")
}
fmt.Fprint(&g.buf, x.GoName)
fmt.Fprint(&g.buf, g.QualifiedGoIdent(x))
default:
fmt.Fprint(&g.buf, x)
}
@ -444,6 +503,27 @@ func (g *GeneratedFile) P(v ...interface{}) {
fmt.Fprintln(&g.buf)
}
// QualifiedGoIdent returns the string to use for a Go identifier.
//
// If the identifier is from a different Go package than the generated file,
// the returned name will be qualified (package.name) and an import statement
// for the identifier's package will be included in the file.
func (g *GeneratedFile) QualifiedGoIdent(ident GoIdent) string {
if ident.GoImportPath == g.goImportPath {
return ident.GoName
}
if packageName, ok := g.packageNames[ident.GoImportPath]; ok {
return string(packageName) + "." + ident.GoName
}
packageName := cleanPackageName(baseName(string(ident.GoImportPath)))
for i, orig := 1, packageName; g.usedPackageNames[packageName]; i++ {
packageName = orig + GoPackageName(strconv.Itoa(i))
}
g.packageNames[ident.GoImportPath] = packageName
g.usedPackageNames[packageName] = true
return string(packageName) + "." + ident.GoName
}
func (g *GeneratedFile) goPackageName(importPath GoImportPath) GoPackageName {
if name, ok := g.packageNames[importPath]; ok {
return name
@ -522,7 +602,7 @@ const (
// field numbers in FileDescriptorProto
filePackageField = 2 // package
fileMessageField = 4 // message_type
fileenumField = 5 // enum_type
fileEnumField = 5 // enum_type
// field numbers in DescriptorProto
messageFieldField = 2 // field
messageMessageField = 3 // nested_type