internal/impl: handle extremely old messages

At some point in time, protoc-gen-go actually emitted an XXX_OneofFuncs
with a different signature. Adjust the logic for handling XXX_OneofFuncs
to not assume that the return arguments are in a specific order.

Change-Id: Idd9c09231c4129c655d4a635bb1ae094896a1ff4
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/226980
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/impl/legacy_aberrant_test.go b/internal/impl/legacy_aberrant_test.go
index c51b0c7..905981a 100644
--- a/internal/impl/legacy_aberrant_test.go
+++ b/internal/impl/legacy_aberrant_test.go
@@ -86,7 +86,7 @@
 	return []protoiface.ExtensionRangeV1{{Start: 10, End: 100}}
 }
 
-func (m *AberrantMessage) XXX_OneofWrappers() []interface{} {
+func (m *AberrantMessage) XXX_OneofFuncs() []interface{} {
 	return []interface{}{
 		(*OneofBool)(nil),
 		(*OneofInt32)(nil),
diff --git a/internal/impl/legacy_message.go b/internal/impl/legacy_message.go
index a723569..06c68e1 100644
--- a/internal/impl/legacy_message.go
+++ b/internal/impl/legacy_message.go
@@ -195,16 +195,15 @@
 
 	// Obtain a list of oneof wrapper types.
 	var oneofWrappers []reflect.Type
-	if fn, ok := t.MethodByName("XXX_OneofFuncs"); ok {
-		vs := fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3]
-		for _, v := range vs.Interface().([]interface{}) {
-			oneofWrappers = append(oneofWrappers, reflect.TypeOf(v))
-		}
-	}
-	if fn, ok := t.MethodByName("XXX_OneofWrappers"); ok {
-		vs := fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0]
-		for _, v := range vs.Interface().([]interface{}) {
-			oneofWrappers = append(oneofWrappers, reflect.TypeOf(v))
+	for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} {
+		if fn, ok := t.MethodByName(method); ok {
+			for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) {
+				if vs, ok := v.Interface().([]interface{}); ok {
+					for _, v := range vs {
+						oneofWrappers = append(oneofWrappers, reflect.TypeOf(v))
+					}
+				}
+			}
 		}
 	}
 
diff --git a/internal/impl/message.go b/internal/impl/message.go
index 65de48a..c1d8902 100644
--- a/internal/impl/message.go
+++ b/internal/impl/message.go
@@ -182,11 +182,14 @@
 
 	// Derive a mapping of oneof wrappers to fields.
 	oneofWrappers := mi.OneofWrappers
-	if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok {
-		oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{})
-	}
-	if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok {
-		oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{})
+	for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} {
+		if fn, ok := reflect.PtrTo(t).MethodByName(method); ok {
+			for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) {
+				if vs, ok := v.Interface().([]interface{}); ok {
+					oneofWrappers = vs
+				}
+			}
+		}
 	}
 	for _, v := range oneofWrappers {
 		tf := reflect.TypeOf(v).Elem()