cmd/protoc-gen-go: generate Enum method even on proto3

A proto2 message can reference a proto3 enum. It is currently cumbersome
to set proto3 enums in proto2 messages. Add the Enum method in all situations
to support this situation. It also removes yet another point of divergence
between proto2 and proto3.

We could consider removing this method if Go ever gets generics,
but that hypothetical future is long ways away.

Change-Id: Ib83bc87e46b49f3271b90bacb2893bb8e278e4f2
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/177257
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/cmd/protoc-gen-go/internal_gengo/main.go b/cmd/protoc-gen-go/internal_gengo/main.go
index 6a48126..397467a 100644
--- a/cmd/protoc-gen-go/internal_gengo/main.go
+++ b/cmd/protoc-gen-go/internal_gengo/main.go
@@ -266,14 +266,17 @@
 	}
 
 	// Enum method.
-	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()
-	}
+	//
+	// NOTE: A pointer value is needed to represent presence in proto2.
+	// Since a proto2 message can reference a proto3 enum, it is useful to
+	// always generate this method (even on proto3 enums) to support that case.
+	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()
+
 	// String method.
 	g.P("func (x ", enum.GoIdent, ") String() string {")
 	g.P("return ", protoimplPackage.Ident("X"), ".EnumStringOf(x.Descriptor(), ", protoreflectPackage.Ident("EnumNumber"), "(x))")
diff --git a/cmd/protoc-gen-go/testdata/comments/deprecated.pb.go b/cmd/protoc-gen-go/testdata/comments/deprecated.pb.go
index df129a2..cf55c78 100644
--- a/cmd/protoc-gen-go/testdata/comments/deprecated.pb.go
+++ b/cmd/protoc-gen-go/testdata/comments/deprecated.pb.go
@@ -28,6 +28,12 @@
 	"DEPRECATED": 0,
 }
 
+func (x DeprecatedEnum) Enum() *DeprecatedEnum {
+	p := new(DeprecatedEnum)
+	*p = x
+	return p
+}
+
 func (x DeprecatedEnum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
diff --git a/cmd/protoc-gen-go/testdata/extensions/proto3/ext3.pb.go b/cmd/protoc-gen-go/testdata/extensions/proto3/ext3.pb.go
index 61fda36..e8cf547 100644
--- a/cmd/protoc-gen-go/testdata/extensions/proto3/ext3.pb.go
+++ b/cmd/protoc-gen-go/testdata/extensions/proto3/ext3.pb.go
@@ -30,6 +30,12 @@
 	"ZERO": 0,
 }
 
+func (x Enum) Enum() *Enum {
+	p := new(Enum)
+	*p = x
+	return p
+}
+
 func (x Enum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
diff --git a/cmd/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go b/cmd/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go
index 36ac2d6..1e13347 100644
--- a/cmd/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go
+++ b/cmd/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go
@@ -29,6 +29,12 @@
 	"E1_ZERO": 0,
 }
 
+func (x E1) Enum() *E1 {
+	p := new(E1)
+	*p = x
+	return p
+}
+
 func (x E1) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
diff --git a/cmd/protoc-gen-go/testdata/proto3/enum.pb.go b/cmd/protoc-gen-go/testdata/proto3/enum.pb.go
index 84de309..a98ab85 100644
--- a/cmd/protoc-gen-go/testdata/proto3/enum.pb.go
+++ b/cmd/protoc-gen-go/testdata/proto3/enum.pb.go
@@ -34,6 +34,12 @@
 	"TWO":  2,
 }
 
+func (x Enum) Enum() *Enum {
+	p := new(Enum)
+	*p = x
+	return p
+}
+
 func (x Enum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
diff --git a/cmd/protoc-gen-go/testdata/proto3/fields.pb.go b/cmd/protoc-gen-go/testdata/proto3/fields.pb.go
index be06063..97a38f8 100644
--- a/cmd/protoc-gen-go/testdata/proto3/fields.pb.go
+++ b/cmd/protoc-gen-go/testdata/proto3/fields.pb.go
@@ -29,6 +29,12 @@
 	"ZERO": 0,
 }
 
+func (x FieldTestMessage_Enum) Enum() *FieldTestMessage_Enum {
+	p := new(FieldTestMessage_Enum)
+	*p = x
+	return p
+}
+
 func (x FieldTestMessage_Enum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
diff --git a/encoding/testprotos/pb3/test.pb.go b/encoding/testprotos/pb3/test.pb.go
index 992de19..1df06ec 100644
--- a/encoding/testprotos/pb3/test.pb.go
+++ b/encoding/testprotos/pb3/test.pb.go
@@ -38,6 +38,12 @@
 	"TEN":  10,
 }
 
+func (x Enum) Enum() *Enum {
+	p := new(Enum)
+	*p = x
+	return p
+}
+
 func (x Enum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
@@ -85,6 +91,12 @@
 	"DIEZ": 10,
 }
 
+func (x Enums_NestedEnum) Enum() *Enums_NestedEnum {
+	p := new(Enums_NestedEnum)
+	*p = x
+	return p
+}
+
 func (x Enums_NestedEnum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
diff --git a/internal/testprotos/conformance/conformance.pb.go b/internal/testprotos/conformance/conformance.pb.go
index 0dc0735..b54a74d 100644
--- a/internal/testprotos/conformance/conformance.pb.go
+++ b/internal/testprotos/conformance/conformance.pb.go
@@ -41,6 +41,12 @@
 	"TEXT_FORMAT": 4,
 }
 
+func (x WireFormat) Enum() *WireFormat {
+	p := new(WireFormat)
+	*p = x
+	return p
+}
+
 func (x WireFormat) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
@@ -102,6 +108,12 @@
 	"TEXT_FORMAT_TEST":                 5,
 }
 
+func (x TestCategory) Enum() *TestCategory {
+	p := new(TestCategory)
+	*p = x
+	return p
+}
+
 func (x TestCategory) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
diff --git a/internal/testprotos/conformance/test_messages_proto3.pb.go b/internal/testprotos/conformance/test_messages_proto3.pb.go
index 9cbfbe9..556efd8 100644
--- a/internal/testprotos/conformance/test_messages_proto3.pb.go
+++ b/internal/testprotos/conformance/test_messages_proto3.pb.go
@@ -41,6 +41,12 @@
 	"FOREIGN_BAZ": 2,
 }
 
+func (x ForeignEnum) Enum() *ForeignEnum {
+	p := new(ForeignEnum)
+	*p = x
+	return p
+}
+
 func (x ForeignEnum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
@@ -88,6 +94,12 @@
 	"NEG": -1,
 }
 
+func (x TestAllTypesProto3_NestedEnum) Enum() *TestAllTypesProto3_NestedEnum {
+	p := new(TestAllTypesProto3_NestedEnum)
+	*p = x
+	return p
+}
+
 func (x TestAllTypesProto3_NestedEnum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
@@ -141,6 +153,12 @@
 	"bAz":       2,
 }
 
+func (x TestAllTypesProto3_AliasedEnum) Enum() *TestAllTypesProto3_AliasedEnum {
+	p := new(TestAllTypesProto3_AliasedEnum)
+	*p = x
+	return p
+}
+
 func (x TestAllTypesProto3_AliasedEnum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
diff --git a/internal/testprotos/test3/test.pb.go b/internal/testprotos/test3/test.pb.go
index ded5e83..31180d0 100644
--- a/internal/testprotos/test3/test.pb.go
+++ b/internal/testprotos/test3/test.pb.go
@@ -38,6 +38,12 @@
 	"FOREIGN_BAZ":  6,
 }
 
+func (x ForeignEnum) Enum() *ForeignEnum {
+	p := new(ForeignEnum)
+	*p = x
+	return p
+}
+
 func (x ForeignEnum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
@@ -85,6 +91,12 @@
 	"NEG": -1,
 }
 
+func (x TestAllTypes_NestedEnum) Enum() *TestAllTypes_NestedEnum {
+	p := new(TestAllTypes_NestedEnum)
+	*p = x
+	return p
+}
+
 func (x TestAllTypes_NestedEnum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
diff --git a/internal/testprotos/test3/test_import.pb.go b/internal/testprotos/test3/test_import.pb.go
index 8376505..a281989 100644
--- a/internal/testprotos/test3/test_import.pb.go
+++ b/internal/testprotos/test3/test_import.pb.go
@@ -29,6 +29,12 @@
 	"IMPORT_ZERO": 0,
 }
 
+func (x ImportEnum) Enum() *ImportEnum {
+	p := new(ImportEnum)
+	*p = x
+	return p
+}
+
 func (x ImportEnum) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
diff --git a/types/known/structpb/struct.pb.go b/types/known/structpb/struct.pb.go
index 08d31bf..9720ade 100644
--- a/types/known/structpb/struct.pb.go
+++ b/types/known/structpb/struct.pb.go
@@ -34,6 +34,12 @@
 	"NULL_VALUE": 0,
 }
 
+func (x NullValue) Enum() *NullValue {
+	p := new(NullValue)
+	*p = x
+	return p
+}
+
 func (x NullValue) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
diff --git a/types/known/typepb/type.pb.go b/types/known/typepb/type.pb.go
index 6aabc9a..6ed50ba 100644
--- a/types/known/typepb/type.pb.go
+++ b/types/known/typepb/type.pb.go
@@ -37,6 +37,12 @@
 	"SYNTAX_PROTO3": 1,
 }
 
+func (x Syntax) Enum() *Syntax {
+	p := new(Syntax)
+	*p = x
+	return p
+}
+
 func (x Syntax) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
@@ -149,6 +155,12 @@
 	"TYPE_SINT64":   18,
 }
 
+func (x Field_Kind) Enum() *Field_Kind {
+	p := new(Field_Kind)
+	*p = x
+	return p
+}
+
 func (x Field_Kind) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }
@@ -201,6 +213,12 @@
 	"CARDINALITY_REPEATED": 3,
 }
 
+func (x Field_Cardinality) Enum() *Field_Cardinality {
+	p := new(Field_Cardinality)
+	*p = x
+	return p
+}
+
 func (x Field_Cardinality) String() string {
 	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
 }