protogen: use protoreflect descriptors
Change the protogen types wrapping FileDescriptorProto et al. to use
protoreflect descriptors instead.
Change-Id: I99fe83b995a0a6f4fc88f03a6e4b827109a2ec80
Reviewed-on: https://go-review.googlesource.com/133815
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/cmd/protoc-gen-go/main.go b/cmd/protoc-gen-go/main.go
index e144aa6..bfae8eb 100644
--- a/cmd/protoc-gen-go/main.go
+++ b/cmd/protoc-gen-go/main.go
@@ -25,9 +25,9 @@
}
func genFile(gen *protogen.Plugin, f *protogen.File) {
- g := gen.NewGeneratedFile(strings.TrimSuffix(f.Desc.GetName(), ".proto")+".pb.go", f.GoImportPath)
+ g := gen.NewGeneratedFile(strings.TrimSuffix(f.Desc.Path(), ".proto")+".pb.go", f.GoImportPath)
g.P("// Code generated by protoc-gen-go. DO NOT EDIT.")
- g.P("// source: ", f.Desc.GetName())
+ g.P("// source: ", f.Desc.Path())
g.P()
g.P("package TODO")
g.P()
diff --git a/protogen/names.go b/protogen/names.go
index ea3d057..0c220bc 100644
--- a/protogen/names.go
+++ b/protogen/names.go
@@ -7,6 +7,8 @@
"strings"
"unicode"
"unicode/utf8"
+
+ "google.golang.org/proto/reflect/protoreflect"
)
// A GoIdent is a Go identifier, consisting of a name and import path.
@@ -17,6 +19,15 @@
func (id GoIdent) String() string { return fmt.Sprintf("%q.%v", id.GoImportPath, id.GoName) }
+// newGoIdent returns the Go identifier for a descriptor.
+func newGoIdent(f *File, d protoreflect.Descriptor) GoIdent {
+ name := strings.TrimPrefix(string(d.FullName()), string(f.Desc.Package())+".")
+ return GoIdent{
+ GoName: camelCase(name),
+ GoImportPath: f.GoImportPath,
+ }
+}
+
// A GoImportPath is the import path of a Go package. e.g., "google.golang.org/genproto/protobuf".
type GoImportPath string
diff --git a/protogen/protogen.go b/protogen/protogen.go
index 2d65ee0..ffba172 100644
--- a/protogen/protogen.go
+++ b/protogen/protogen.go
@@ -28,6 +28,9 @@
descpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin"
"golang.org/x/tools/go/ast/astutil"
+ "google.golang.org/proto/reflect/protoreflect"
+ "google.golang.org/proto/reflect/protoregistry"
+ "google.golang.org/proto/reflect/prototype"
)
// Run executes a function as a protoc plugin.
@@ -88,6 +91,8 @@
Files []*File
filesByName map[string]*File
+ fileReg *protoregistry.Files
+
packageImportPath string // Go import path of the package we're generating code for.
genFiles []*GeneratedFile
@@ -99,6 +104,7 @@
gen := &Plugin{
Request: req,
filesByName: make(map[string]*File),
+ fileReg: protoregistry.NewFiles(),
}
// TODO: Figure out how to pass parameters to the generator.
@@ -130,8 +136,11 @@
}
for _, fdesc := range gen.Request.ProtoFile {
- f := newFile(gen, fdesc)
- name := f.Desc.GetName()
+ f, err := newFile(gen, fdesc)
+ if err != nil {
+ return nil, err
+ }
+ name := f.Desc.Path()
if gen.filesByName[name] != nil {
return nil, fmt.Errorf("duplicate file name: %q", name)
}
@@ -186,44 +195,45 @@
// A File describes a .proto source file.
type File struct {
- Desc *descpb.FileDescriptorProto // TODO: protoreflect.FileDescriptor
+ Desc protoreflect.FileDescriptor
GoImportPath GoImportPath // import path of this file's Go package
Messages []*Message // top-level message declarations
Generate bool // true if we should generate code for this file
}
-func newFile(gen *Plugin, p *descpb.FileDescriptorProto) *File {
+func newFile(gen *Plugin, p *descpb.FileDescriptorProto) (*File, error) {
+ desc, err := prototype.NewFileFromDescriptorProto(p, gen.fileReg)
+ if err != nil {
+ return nil, fmt.Errorf("invalid FileDescriptorProto %q: %v", p.GetName(), err)
+ }
+ if err := gen.fileReg.Register(desc); err != nil {
+ return nil, fmt.Errorf("cannot register descriptor %q: %v", p.GetName(), err)
+ }
f := &File{
- Desc: p,
+ Desc: desc,
}
- for i, mdesc := range p.MessageType {
- f.Messages = append(f.Messages, newMessage(gen, f, nil, mdesc, i))
+ for i, mdescs := 0, desc.Messages(); i < mdescs.Len(); i++ {
+ f.Messages = append(f.Messages, newMessage(gen, f, nil, mdescs.Get(i), i))
}
- return f
+ return f, nil
}
// A Message describes a message.
type Message struct {
- Desc *descpb.DescriptorProto // TODO: protoreflect.MessageDescriptor
+ Desc protoreflect.MessageDescriptor
GoIdent GoIdent // name of the generated Go type
Messages []*Message // nested message declarations
}
-func newMessage(gen *Plugin, f *File, parent *Message, p *descpb.DescriptorProto, index int) *Message {
+func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.MessageDescriptor, index int) *Message {
m := &Message{
- Desc: p,
- GoIdent: GoIdent{
- GoName: camelCase(p.GetName()),
- GoImportPath: f.GoImportPath,
- },
+ Desc: desc,
+ GoIdent: newGoIdent(f, desc),
}
- if parent != nil {
- m.GoIdent.GoName = parent.GoIdent.GoName + "_" + m.GoIdent.GoName
- }
- for i, nested := range p.GetNestedType() {
- m.Messages = append(m.Messages, newMessage(gen, f, m, nested, i))
+ for i, mdescs := 0, desc.Messages(); i < mdescs.Len(); i++ {
+ m.Messages = append(m.Messages, newMessage(gen, f, m, mdescs.Get(i), i))
}
return m
}