proto: add MessageV1, MessageV2, and MessageReflect

The MessageV1 and MessageV2 functions convert to/from the v1 and v2
message interfaces.
The MessageReflect function provides a reflective view over message.
These functions do not have an "Of" suffix to be consistent with
the existing MessageName and MessageType functions.

Furthermore, we drop the "Of" suffix from functions in the descriptor
package to be consistent. This is a safe change since none of those
functions have seen a stable release.

We move the descriptor.GeneratedXXX types to the proto package
for documentation purposes.

Fixes #956

Change-Id: I566b74367798e2e3399db9902b58ffeb673199ca
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/219137
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/descriptor/descriptor.go b/descriptor/descriptor.go
index 3543da5..53390ea 100644
--- a/descriptor/descriptor.go
+++ b/descriptor/descriptor.go
@@ -25,7 +25,10 @@
 )
 
 // Message is proto.Message with a method to return its descriptor.
-// Not every message is guaranteed to implement this interface.
+//
+// Deprecated: The Descriptor method may not be generated by future
+// versions of protoc-gen-go, meaning that this interface may not
+// be implemented by many concrete message types.
 type Message interface {
 	proto.Message
 	Descriptor() ([]byte, []int)
@@ -34,18 +37,15 @@
 // ForMessage returns the file descriptor proto containing
 // the message and the message descriptor proto for the message itself.
 // The returned proto messages must not be mutated.
+//
+// Deprecated: Not all concrete message types satisfy the Message interface.
+// Use MessageDescriptorProto instead. If possible, the calling code should
+// be rewritten to use protobuf reflection instead.
+// See package "google.golang.org/protobuf/reflect/protoreflect" for details.
 func ForMessage(m Message) (*descriptorpb.FileDescriptorProto, *descriptorpb.DescriptorProto) {
-	return MessageDescriptorProtoOf(m)
+	return MessageDescriptorProto(m)
 }
 
-// GeneratedEnum is any enum type generated by protoc-gen-go
-// which is a named int32 kind.
-type GeneratedEnum interface{}
-
-// GeneratedMessage is any message type generated by protoc-gen-go
-// which is a pointer to a named struct kind.
-type GeneratedMessage interface{}
-
 type rawDesc struct {
 	fileDesc []byte
 	indexes  []int
@@ -99,10 +99,10 @@
 	return file, idxs
 }
 
-// EnumRawDescriptorOf returns the GZIP'd raw file descriptor containing the
+// EnumRawDescriptor returns the GZIP'd raw file descriptor containing the
 // enum and the index path to reach the enum declaration.
 // The returned slices must not be mutated.
-func EnumRawDescriptorOf(e GeneratedEnum) ([]byte, []int) {
+func EnumRawDescriptor(e proto.GeneratedEnum) ([]byte, []int) {
 	if ev, ok := e.(interface{ EnumDescriptor() ([]byte, []int) }); ok {
 		return ev.EnumDescriptor()
 	}
@@ -110,10 +110,10 @@
 	return deriveRawDescriptor(ed.Descriptor())
 }
 
-// MessageRawDescriptorOf returns the GZIP'd raw file descriptor containing
+// MessageRawDescriptor returns the GZIP'd raw file descriptor containing
 // the message and the index path to reach the message declaration.
 // The returned slices must not be mutated.
-func MessageRawDescriptorOf(m GeneratedMessage) ([]byte, []int) {
+func MessageRawDescriptor(m proto.GeneratedMessage) ([]byte, []int) {
 	if mv, ok := m.(interface{ Descriptor() ([]byte, []int) }); ok {
 		return mv.Descriptor()
 	}
@@ -148,11 +148,11 @@
 	return fd
 }
 
-// EnumDescriptorProtoOf returns the file descriptor proto containing
+// EnumDescriptorProto returns the file descriptor proto containing
 // the enum and the enum descriptor proto for the enum itself.
 // The returned proto messages must not be mutated.
-func EnumDescriptorProtoOf(e GeneratedEnum) (*descriptorpb.FileDescriptorProto, *descriptorpb.EnumDescriptorProto) {
-	rawDesc, idxs := EnumRawDescriptorOf(e)
+func EnumDescriptorProto(e proto.GeneratedEnum) (*descriptorpb.FileDescriptorProto, *descriptorpb.EnumDescriptorProto) {
+	rawDesc, idxs := EnumRawDescriptor(e)
 	if rawDesc == nil || idxs == nil {
 		return nil, nil
 	}
@@ -168,11 +168,11 @@
 	return fd, ed
 }
 
-// MessageDescriptorProtoOf returns the file descriptor proto containing
+// MessageDescriptorProto returns the file descriptor proto containing
 // the message and the message descriptor proto for the message itself.
 // The returned proto messages must not be mutated.
-func MessageDescriptorProtoOf(m GeneratedMessage) (*descriptorpb.FileDescriptorProto, *descriptorpb.DescriptorProto) {
-	rawDesc, idxs := MessageRawDescriptorOf(m)
+func MessageDescriptorProto(m proto.GeneratedMessage) (*descriptorpb.FileDescriptorProto, *descriptorpb.DescriptorProto) {
+	rawDesc, idxs := MessageRawDescriptor(m)
 	if rawDesc == nil || idxs == nil {
 		return nil, nil
 	}
diff --git a/descriptor/descriptor_test.go b/descriptor/descriptor_test.go
index c11680c..2808397 100644
--- a/descriptor/descriptor_test.go
+++ b/descriptor/descriptor_test.go
@@ -13,7 +13,7 @@
 	descpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
 )
 
-func TestEnumDescriptorOf(t *testing.T) {
+func TestEnumDescriptor(t *testing.T) {
 	tests := []struct {
 		enum protoreflect.Enum
 		idxs []int
@@ -37,19 +37,19 @@
 	for _, tt := range tests {
 		e := struct{ protoreflect.Enum }{tt.enum} // v2-only enum
 
-		_, idxs := EnumRawDescriptorOf(e)
+		_, idxs := EnumRawDescriptor(e)
 		if diff := cmp.Diff(tt.idxs, idxs); diff != "" {
 			t.Errorf("path index mismatch (-want +got):\n%v", diff)
 		}
 
-		_, ed := EnumDescriptorProtoOf(e)
+		_, ed := EnumDescriptorProto(e)
 		if ed.GetName() != tt.name {
 			t.Errorf("mismatching enum name: got %v, want %v", ed.GetName(), tt.name)
 		}
 	}
 }
 
-func TestMessageDescriptorOf(t *testing.T) {
+func TestMessageDescriptor(t *testing.T) {
 	tests := []struct {
 		message protoreflect.ProtoMessage
 		idxs    []int
@@ -72,12 +72,12 @@
 	for _, tt := range tests {
 		m := struct{ protoreflect.ProtoMessage }{tt.message} // v2-only message
 
-		_, idxs := MessageRawDescriptorOf(m)
+		_, idxs := MessageRawDescriptor(m)
 		if diff := cmp.Diff(tt.idxs, idxs); diff != "" {
 			t.Errorf("path index mismatch (-want +got):\n%v", diff)
 		}
 
-		_, md := MessageDescriptorProtoOf(m)
+		_, md := MessageDescriptorProto(m)
 		if md.GetName() != tt.name {
 			t.Errorf("mismatching message name: got %v, want %v", md.GetName(), tt.name)
 		}
diff --git a/proto/proto.go b/proto/proto.go
index a642816..5ce96ec 100644
--- a/proto/proto.go
+++ b/proto/proto.go
@@ -13,7 +13,7 @@
 package proto
 
 import (
-	"google.golang.org/protobuf/proto"
+	protoV2 "google.golang.org/protobuf/proto"
 	"google.golang.org/protobuf/reflect/protoreflect"
 	"google.golang.org/protobuf/runtime/protoiface"
 	"google.golang.org/protobuf/runtime/protoimpl"
@@ -26,9 +26,47 @@
 	ProtoPackageIsVersion4 = true
 )
 
+// GeneratedEnum is any enum type generated by protoc-gen-go
+// which is a named int32 kind.
+// This type exists for documentation purposes.
+type GeneratedEnum interface{}
+
+// GeneratedMessage is any message type generated by protoc-gen-go
+// which is a pointer to a named struct kind.
+// This type exists for documentation purposes.
+type GeneratedMessage interface{}
+
 // Message is a protocol buffer message.
+//
+// This is the v1 version of the message interface and is marginally better
+// than an empty interface as it lacks any method to programatically interact
+// with the contents of the message.
+//
+// A v2 message is declared in "google.golang.org/protobuf/proto".Message and
+// exposes protobuf reflection as a first-class feature of the interface.
+//
+// To convert a v1 message to a v2 message, use the MessageV2 function.
+// To convert a v2 message to a v1 message, use the MessageV1 function.
 type Message = protoiface.MessageV1
 
+// MessageV1 converts either a v1 or v2 message to a v1 message.
+// It returns nil if m is nil.
+func MessageV1(m GeneratedMessage) protoiface.MessageV1 {
+	return protoimpl.X.ProtoMessageV1Of(m)
+}
+
+// MessageV2 converts either a v1 or v2 message to a v2 message.
+// It returns nil if m is nil.
+func MessageV2(m GeneratedMessage) protoV2.Message {
+	return protoimpl.X.ProtoMessageV2Of(m)
+}
+
+// MessageReflect returns a reflective view for a message.
+// It returns nil if m is nil.
+func MessageReflect(m Message) protoreflect.Message {
+	return protoimpl.X.MessageOf(m)
+}
+
 // Marshaler is implemented by messages that can marshal themselves.
 // This interface is used by the following functions: Size, Marshal,
 // Buffer.Marshal, and Buffer.EncodeMessage.
@@ -80,8 +118,8 @@
 	return true
 }
 
-func checkRequiredNotSet(m proto.Message) error {
-	if err := proto.IsInitialized(m); err != nil {
+func checkRequiredNotSet(m protoV2.Message) error {
+	if err := protoV2.IsInitialized(m); err != nil {
 		return &RequiredNotSetError{err: err}
 	}
 	return nil
@@ -113,7 +151,7 @@
 		m.Merge(src)
 		return
 	}
-	proto.Merge(
+	protoV2.Merge(
 		protoimpl.X.ProtoMessageV2Of(dst),
 		protoimpl.X.ProtoMessageV2Of(src),
 	)
@@ -135,7 +173,7 @@
 // Maps are equal if they have the same set of keys, where the pair of values
 // for each key is also equal.
 func Equal(x, y Message) bool {
-	return proto.Equal(
+	return protoV2.Equal(
 		protoimpl.X.ProtoMessageV2Of(x),
 		protoimpl.X.ProtoMessageV2Of(y),
 	)