reflect/protodesc: enforce strict validation

Hyrum's Law dictates that if we do not prevent naughty behavior,
people will rely on it. If we do not validate that the provided
file descriptor is correct today, it will be near impossible
to add proper validation checks later on.

The logic added validates that the provided file descriptor is
correct according to the same semantics as protoc,
which was reversed engineered to derive the set of rules implemented here.
The rules are unfortunately complicated because protobuf is a language
full of many non-orthogonal features. While our logic is complicated,
it is still 1/7th the size of the equivalent C++ code!

Change-Id: I6acc5dc3bd2e4c6bea6cd9e81214f8104402602a
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/184837
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/filedesc/desc_test.go b/internal/filedesc/desc_test.go
index 5bea386..66ce518 100644
--- a/internal/filedesc/desc_test.go
+++ b/internal/filedesc/desc_test.go
@@ -39,22 +39,8 @@
 		MessageType: []*descriptorpb.DescriptorProto{{
 			Name: scalar.String("A"),
 			Options: &descriptorpb.MessageOptions{
-				MapEntry:   scalar.Bool(true),
 				Deprecated: scalar.Bool(true),
 			},
-			Field: []*descriptorpb.FieldDescriptorProto{{
-				Name:    scalar.String("key"),
-				Number:  scalar.Int32(1),
-				Options: &descriptorpb.FieldOptions{Deprecated: scalar.Bool(true)},
-				Label:   descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
-				Type:    descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
-			}, {
-				Name:     scalar.String("value"),
-				Number:   scalar.Int32(2),
-				Label:    descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
-				Type:     descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
-				TypeName: scalar.String(".test.B"),
-			}},
 		}, {
 			Name: scalar.String("B"),
 			Field: []*descriptorpb.FieldDescriptorProto{{
@@ -86,7 +72,7 @@
 				Number:   scalar.Int32(4),
 				Label:    descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
 				Type:     descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
-				TypeName: scalar.String(".test.A"),
+				TypeName: scalar.String(".test.B.FieldFourEntry"),
 			}, {
 				Name:    scalar.String("field_five"),
 				Number:  scalar.Int32(5),
@@ -119,6 +105,24 @@
 				{Start: scalar.Int32(1000), End: scalar.Int32(2000)},
 				{Start: scalar.Int32(3000), End: scalar.Int32(3001), Options: new(descriptorpb.ExtensionRangeOptions)},
 			},
+			NestedType: []*descriptorpb.DescriptorProto{{
+				Name: scalar.String("FieldFourEntry"),
+				Field: []*descriptorpb.FieldDescriptorProto{{
+					Name:   scalar.String("key"),
+					Number: scalar.Int32(1),
+					Label:  descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
+					Type:   descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
+				}, {
+					Name:     scalar.String("value"),
+					Number:   scalar.Int32(2),
+					Label:    descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
+					Type:     descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
+					TypeName: scalar.String(".test.B"),
+				}},
+				Options: &descriptorpb.MessageOptions{
+					MapEntry: scalar.Bool(true),
+				},
+			}},
 		}, {
 			Name: scalar.String("C"),
 			NestedType: []*descriptorpb.DescriptorProto{{
@@ -168,9 +172,9 @@
 			Name:     scalar.String("X"),
 			Number:   scalar.Int32(1000),
 			Label:    descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
-			Type:     descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
+			Type:     descriptorpb.FieldDescriptorProto_Type(pref.EnumKind).Enum(),
 			Options:  &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
-			TypeName: scalar.String(".test.C"),
+			TypeName: scalar.String(".test.E1"),
 			Extendee: scalar.String(".test.B"),
 		}},
 		Service: []*descriptorpb.ServiceDescriptorProto{{
@@ -239,57 +243,10 @@
 				"Name":          pref.Name("A"),
 				"FullName":      pref.FullName("test.A"),
 				"IsPlaceholder": false,
-				"IsMapEntry":    true,
+				"IsMapEntry":    false,
 				"Options": &descriptorpb.MessageOptions{
-					MapEntry:   scalar.Bool(true),
 					Deprecated: scalar.Bool(true),
 				},
-				"Fields": M{
-					"Len": 2,
-					"ByNumber:1": M{
-						"Parent":            M{"FullName": pref.FullName("test.A")},
-						"Index":             0,
-						"Name":              pref.Name("key"),
-						"FullName":          pref.FullName("test.A.key"),
-						"Number":            pref.FieldNumber(1),
-						"Cardinality":       pref.Optional,
-						"Kind":              pref.StringKind,
-						"Options":           &descriptorpb.FieldOptions{Deprecated: scalar.Bool(true)},
-						"HasJSONName":       false,
-						"JSONName":          "key",
-						"IsPacked":          false,
-						"IsList":            false,
-						"IsMap":             false,
-						"IsExtension":       false,
-						"IsWeak":            false,
-						"Default":           "",
-						"ContainingOneof":   nil,
-						"ContainingMessage": M{"FullName": pref.FullName("test.A")},
-						"Message":           nil,
-						"Enum":              nil,
-					},
-					"ByNumber:2": M{
-						"Parent":            M{"FullName": pref.FullName("test.A")},
-						"Index":             1,
-						"Name":              pref.Name("value"),
-						"FullName":          pref.FullName("test.A.value"),
-						"Number":            pref.FieldNumber(2),
-						"Cardinality":       pref.Optional,
-						"Kind":              pref.MessageKind,
-						"JSONName":          "value",
-						"IsPacked":          false,
-						"IsList":            false,
-						"IsMap":             false,
-						"IsExtension":       false,
-						"IsWeak":            false,
-						"Default":           nil,
-						"ContainingOneof":   nil,
-						"ContainingMessage": M{"FullName": pref.FullName("test.A")},
-						"Message":           M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
-						"Enum":              nil,
-					},
-					"ByNumber:3": nil,
-				},
 				"Oneofs":          M{"Len": 0},
 				"RequiredNumbers": M{"Len": 0},
 				"ExtensionRanges": M{"Len": 0},
@@ -339,7 +296,7 @@
 						"MapKey":      M{"Kind": pref.StringKind},
 						"MapValue":    M{"Kind": pref.MessageKind, "Message": M{"FullName": pref.FullName("test.B")}},
 						"Default":     nil,
-						"Message":     M{"FullName": pref.FullName("test.A"), "IsPlaceholder": false},
+						"Message":     M{"FullName": pref.FullName("test.B.FieldFourEntry"), "IsPlaceholder": false},
 					},
 					"ByNumber:5": M{
 						"Cardinality": pref.Repeated,
@@ -417,6 +374,56 @@
 				},
 				"ExtensionRangeOptions:0": (*descriptorpb.ExtensionRangeOptions)(nil),
 				"ExtensionRangeOptions:1": new(descriptorpb.ExtensionRangeOptions),
+				"Messages": M{
+					"Get:0": M{
+						"Fields": M{
+							"Len": 2,
+							"ByNumber:1": M{
+								"Parent":            M{"FullName": pref.FullName("test.B.FieldFourEntry")},
+								"Index":             0,
+								"Name":              pref.Name("key"),
+								"FullName":          pref.FullName("test.B.FieldFourEntry.key"),
+								"Number":            pref.FieldNumber(1),
+								"Cardinality":       pref.Optional,
+								"Kind":              pref.StringKind,
+								"Options":           (*descriptorpb.FieldOptions)(nil),
+								"HasJSONName":       false,
+								"JSONName":          "key",
+								"IsPacked":          false,
+								"IsList":            false,
+								"IsMap":             false,
+								"IsExtension":       false,
+								"IsWeak":            false,
+								"Default":           "",
+								"ContainingOneof":   nil,
+								"ContainingMessage": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
+								"Message":           nil,
+								"Enum":              nil,
+							},
+							"ByNumber:2": M{
+								"Parent":            M{"FullName": pref.FullName("test.B.FieldFourEntry")},
+								"Index":             1,
+								"Name":              pref.Name("value"),
+								"FullName":          pref.FullName("test.B.FieldFourEntry.value"),
+								"Number":            pref.FieldNumber(2),
+								"Cardinality":       pref.Optional,
+								"Kind":              pref.MessageKind,
+								"JSONName":          "value",
+								"IsPacked":          false,
+								"IsList":            false,
+								"IsMap":             false,
+								"IsExtension":       false,
+								"IsWeak":            false,
+								"Default":           nil,
+								"ContainingOneof":   nil,
+								"ContainingMessage": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
+								"Message":           M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
+								"Enum":              nil,
+							},
+							"ByNumber:3": nil,
+						},
+					},
+				},
 			},
 			"Get:2": M{
 				"Name":  pref.Name("C"),
@@ -475,7 +482,7 @@
 				"Name":              pref.Name("X"),
 				"Number":            pref.FieldNumber(1000),
 				"Cardinality":       pref.Repeated,
-				"Kind":              pref.MessageKind,
+				"Kind":              pref.EnumKind,
 				"IsExtension":       true,
 				"IsPacked":          true,
 				"IsList":            true,
@@ -484,7 +491,7 @@
 				"MapValue":          nil,
 				"ContainingOneof":   nil,
 				"ContainingMessage": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
-				"Message":           M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
+				"Enum":              M{"FullName": pref.FullName("test.E1"), "IsPlaceholder": false},
 				"Options":           &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
 			},
 		},
@@ -598,22 +605,7 @@
 	Path:    "path/to/file.proto"
 	Package: test
 	Messages: [{
-		Name:       A
-		IsMapEntry: true
-		Fields: [{
-			Name:        key
-			Number:      1
-			Cardinality: optional
-			Kind:        string
-			JSONName:    "key"
-		}, {
-			Name:        value
-			Number:      2
-			Cardinality: optional
-			Kind:        message
-			JSONName:    "value"
-			Message:     test.B
-		}]
+		Name: A
 	}, {
 		Name: B
 		Fields: [{
@@ -680,6 +672,24 @@
 		ReservedRanges:  [100:200, 300]
 		RequiredNumbers: [6]
 		ExtensionRanges: [1000:2000, 3000]
+		Messages: [{
+			Name:       FieldFourEntry
+			IsMapEntry: true
+			Fields: [{
+				Name:        key
+				Number:      1
+				Cardinality: optional
+				Kind:        string
+				JSONName:    "key"
+			}, {
+				Name:        value
+				Number:      2
+				Cardinality: optional
+				Kind:        message
+				JSONName:    "value"
+				Message:     test.B
+			}]
+		}]
 	}, {
 		Name: C
 		Messages: [{
@@ -727,13 +737,13 @@
 		Name:        X
 		Number:      1000
 		Cardinality: repeated
-		Kind:        message
+		Kind:        enum
 		JSONName:    "X"
 		IsPacked:    true
 		IsExtension: true
 		IsList:      true
 		Extendee:    test.B
-		Message:     test.C
+		Enum:        test.E1
 	}]
 	Services: [{
 		Name: S