cmd/protoc-gen-go: register with the v2 registry for descriptor

By passing the global registries to fileinit.Builder, the Build
method can register the newly constructed descriptors on our behalf.
As a result, we can stop registering with the v1 registries as well.

We only do this for descriptor proto to remove another dependency on v1.
We deliberately keep the v1 registration logic for now to make it easy
to patch away this new behavior.

Change-Id: Ic6aa8ffba3d2d0abe08a61fc5e1c9ca7668e0988
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/168000
Reviewed-by: Herbie Ong <herbie@google.com>
diff --git a/cmd/protoc-gen-go/internal_gengo/main.go b/cmd/protoc-gen-go/internal_gengo/main.go
index 7a28ae6..70ecbc9 100644
--- a/cmd/protoc-gen-go/internal_gengo/main.go
+++ b/cmd/protoc-gen-go/internal_gengo/main.go
@@ -778,6 +778,11 @@
 // genInitFunction generates an init function that registers the types in the
 // generated file with the proto package.
 func genInitFunction(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo) {
+	// TODO: Remove this function when we always register with v2.
+	if isDescriptor(f.File) {
+		return
+	}
+
 	g.P("func init() {")
 	g.P(protoPackage.Ident("RegisterFile"), "(", strconv.Quote(f.Desc.Path()), ", ", f.descriptorGzipVar, ")")
 	for _, enum := range f.allEnums {
diff --git a/cmd/protoc-gen-go/internal_gengo/reflect.go b/cmd/protoc-gen-go/internal_gengo/reflect.go
index 3e5300c..7f2d25f 100644
--- a/cmd/protoc-gen-go/internal_gengo/reflect.go
+++ b/cmd/protoc-gen-go/internal_gengo/reflect.go
@@ -24,10 +24,11 @@
 const minimumVersion = 0
 
 const (
-	reflectPackage      = protogen.GoImportPath("reflect")
-	protoimplPackage    = protogen.GoImportPath("github.com/golang/protobuf/v2/runtime/protoimpl")
-	protoreflectPackage = protogen.GoImportPath("github.com/golang/protobuf/v2/reflect/protoreflect")
-	prototypePackage    = protogen.GoImportPath("github.com/golang/protobuf/v2/internal/prototype")
+	reflectPackage       = protogen.GoImportPath("reflect")
+	protoimplPackage     = protogen.GoImportPath("github.com/golang/protobuf/v2/runtime/protoimpl")
+	protoreflectPackage  = protogen.GoImportPath("github.com/golang/protobuf/v2/reflect/protoreflect")
+	protoregistryPackage = protogen.GoImportPath("github.com/golang/protobuf/v2/reflect/protoregistry")
+	prototypePackage     = protogen.GoImportPath("github.com/golang/protobuf/v2/internal/prototype")
 )
 
 // TODO: Add support for proto options.
@@ -179,6 +180,11 @@
 	if len(f.allExtensions) > 0 {
 		g.P("ExtensionOutputTypes: extensionTypes,")
 	}
+	if isDescriptor(f.File) {
+		// TODO: Enable this for all protos.
+		g.P("FilesRegistry: ", protoregistryPackage.Ident("GlobalFiles"), ",")
+		g.P("TypesRegistry: ", protoregistryPackage.Ident("GlobalTypes"), ",")
+	}
 	g.P("}.Init()")
 
 	// Copy the local list of message types into the global array.
@@ -190,8 +196,6 @@
 		g.P("}")
 	}
 
-	// TODO: Add v2 registration and stop v1 registration in genInitFunction.
-
 	// The descriptor proto needs to register the option types with the
 	// prototype so that the package can properly handle those option types.
 	if isDescriptor(f.File) {
diff --git a/internal/fileinit/desc.go b/internal/fileinit/desc.go
index 550cae1..dbfe377 100644
--- a/internal/fileinit/desc.go
+++ b/internal/fileinit/desc.go
@@ -19,6 +19,7 @@
 	pfmt "github.com/golang/protobuf/v2/internal/typefmt"
 	"github.com/golang/protobuf/v2/proto"
 	pref "github.com/golang/protobuf/v2/reflect/protoreflect"
+	preg "github.com/golang/protobuf/v2/reflect/protoregistry"
 )
 
 // FileBuilder construct a protoreflect.FileDescriptor from the
@@ -113,9 +114,12 @@
 	// in "flattened ordering".
 	ExtensionOutputTypes []pref.ExtensionType
 
-	// TODO: Provide ability for FileBuilder to handle registration?
-	// FilesRegistry *pref.Files
-	// TypesRegistry *pref.Types
+	// FilesRegistry is the file registry to register the file descriptor.
+	// If nil, no registration occurs.
+	FilesRegistry *preg.Files
+	// TypesRegistry is the types registry to register each type descriptor.
+	// If nil, no registration occurs.
+	TypesRegistry *preg.Types
 }
 
 // Init constructs a FileDescriptor given the parameters set in FileBuilder.
@@ -124,6 +128,7 @@
 func (fb FileBuilder) Init() pref.FileDescriptor {
 	fd := newFileDesc(fb)
 
+	// Keep v1 and v2 extension descriptors in sync.
 	if fb.LegacyExtensions != nil {
 		for i := range fd.allExtensions {
 			fd.allExtensions[i].legacyDesc = &fb.LegacyExtensions[i]
@@ -131,6 +136,7 @@
 		}
 	}
 
+	// Copy type descriptors to the output.
 	for i := range fd.allEnums {
 		fb.EnumOutputTypes[i] = &fd.allEnums[i]
 	}
@@ -140,6 +146,31 @@
 	for i := range fd.allExtensions {
 		fb.ExtensionOutputTypes[i] = &fd.allExtensions[i]
 	}
+
+	// Register file and type descriptors.
+	if fb.FilesRegistry != nil {
+		if err := fb.FilesRegistry.Register(fd); err != nil {
+			panic(err)
+		}
+	}
+	if fb.TypesRegistry != nil {
+		for i := range fd.allEnums {
+			if err := fb.TypesRegistry.Register(&fd.allEnums[i]); err != nil {
+				panic(err)
+			}
+		}
+		for i := range fd.allMessages {
+			if err := fb.TypesRegistry.Register(&fd.allMessages[i]); err != nil {
+				panic(err)
+			}
+		}
+		for i := range fd.allExtensions {
+			if err := fb.TypesRegistry.Register(&fd.allExtensions[i]); err != nil {
+				panic(err)
+			}
+		}
+	}
+
 	return fd
 }
 
diff --git a/types/descriptor/descriptor.pb.go b/types/descriptor/descriptor.pb.go
index f5df250..d9f8019 100644
--- a/types/descriptor/descriptor.pb.go
+++ b/types/descriptor/descriptor.pb.go
@@ -4,10 +4,10 @@
 package descriptor_proto
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoapi "github.com/golang/protobuf/protoapi"
 	prototype "github.com/golang/protobuf/v2/internal/prototype"
 	protoreflect "github.com/golang/protobuf/v2/reflect/protoreflect"
+	protoregistry "github.com/golang/protobuf/v2/reflect/protoregistry"
 	protoimpl "github.com/golang/protobuf/v2/runtime/protoimpl"
 	reflect "reflect"
 )
@@ -2386,43 +2386,6 @@
 	return 0
 }
 
-func init() {
-	proto.RegisterFile("google/protobuf/descriptor.proto", xxx_File_google_protobuf_descriptor_proto_rawdesc_gzipped)
-	proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Type", FieldDescriptorProto_Type_name, FieldDescriptorProto_Type_value)
-	proto.RegisterEnum("google.protobuf.FieldDescriptorProto_Label", FieldDescriptorProto_Label_name, FieldDescriptorProto_Label_value)
-	proto.RegisterEnum("google.protobuf.FileOptions_OptimizeMode", FileOptions_OptimizeMode_name, FileOptions_OptimizeMode_value)
-	proto.RegisterEnum("google.protobuf.FieldOptions_CType", FieldOptions_CType_name, FieldOptions_CType_value)
-	proto.RegisterEnum("google.protobuf.FieldOptions_JSType", FieldOptions_JSType_name, FieldOptions_JSType_value)
-	proto.RegisterEnum("google.protobuf.MethodOptions_IdempotencyLevel", MethodOptions_IdempotencyLevel_name, MethodOptions_IdempotencyLevel_value)
-	proto.RegisterType((*FileDescriptorSet)(nil), "google.protobuf.FileDescriptorSet")
-	proto.RegisterType((*FileDescriptorProto)(nil), "google.protobuf.FileDescriptorProto")
-	proto.RegisterType((*DescriptorProto)(nil), "google.protobuf.DescriptorProto")
-	proto.RegisterType((*ExtensionRangeOptions)(nil), "google.protobuf.ExtensionRangeOptions")
-	proto.RegisterType((*FieldDescriptorProto)(nil), "google.protobuf.FieldDescriptorProto")
-	proto.RegisterType((*OneofDescriptorProto)(nil), "google.protobuf.OneofDescriptorProto")
-	proto.RegisterType((*EnumDescriptorProto)(nil), "google.protobuf.EnumDescriptorProto")
-	proto.RegisterType((*EnumValueDescriptorProto)(nil), "google.protobuf.EnumValueDescriptorProto")
-	proto.RegisterType((*ServiceDescriptorProto)(nil), "google.protobuf.ServiceDescriptorProto")
-	proto.RegisterType((*MethodDescriptorProto)(nil), "google.protobuf.MethodDescriptorProto")
-	proto.RegisterType((*FileOptions)(nil), "google.protobuf.FileOptions")
-	proto.RegisterType((*MessageOptions)(nil), "google.protobuf.MessageOptions")
-	proto.RegisterType((*FieldOptions)(nil), "google.protobuf.FieldOptions")
-	proto.RegisterType((*OneofOptions)(nil), "google.protobuf.OneofOptions")
-	proto.RegisterType((*EnumOptions)(nil), "google.protobuf.EnumOptions")
-	proto.RegisterType((*EnumValueOptions)(nil), "google.protobuf.EnumValueOptions")
-	proto.RegisterType((*ServiceOptions)(nil), "google.protobuf.ServiceOptions")
-	proto.RegisterType((*MethodOptions)(nil), "google.protobuf.MethodOptions")
-	proto.RegisterType((*UninterpretedOption)(nil), "google.protobuf.UninterpretedOption")
-	proto.RegisterType((*SourceCodeInfo)(nil), "google.protobuf.SourceCodeInfo")
-	proto.RegisterType((*GeneratedCodeInfo)(nil), "google.protobuf.GeneratedCodeInfo")
-	proto.RegisterType((*DescriptorProto_ExtensionRange)(nil), "google.protobuf.DescriptorProto.ExtensionRange")
-	proto.RegisterType((*DescriptorProto_ReservedRange)(nil), "google.protobuf.DescriptorProto.ReservedRange")
-	proto.RegisterType((*EnumDescriptorProto_EnumReservedRange)(nil), "google.protobuf.EnumDescriptorProto.EnumReservedRange")
-	proto.RegisterType((*UninterpretedOption_NamePart)(nil), "google.protobuf.UninterpretedOption.NamePart")
-	proto.RegisterType((*SourceCodeInfo_Location)(nil), "google.protobuf.SourceCodeInfo.Location")
-	proto.RegisterType((*GeneratedCodeInfo_Annotation)(nil), "google.protobuf.GeneratedCodeInfo.Annotation")
-}
-
 var xxx_File_google_protobuf_descriptor_proto_rawdesc = []byte{
 	// 7580 bytes of the wire-encoded FileDescriptorProto
 	0x0a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
@@ -3002,6 +2965,8 @@
 		DependencyIndexes:  xxx_File_google_protobuf_descriptor_proto_depIdxs,
 		EnumOutputTypes:    xxx_File_google_protobuf_descriptor_proto_enumTypes,
 		MessageOutputTypes: messageTypes,
+		FilesRegistry:      protoregistry.GlobalFiles,
+		TypesRegistry:      protoregistry.GlobalTypes,
 	}.Init()
 	messageGoTypes := xxx_File_google_protobuf_descriptor_proto_goTypes[6:][:27]
 	for i, mt := range messageTypes {